Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2007 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #import "config.h"
     27 #import "ThreadCheck.h"
     28 
     29 #import "StringHash.h"
     30 #import <wtf/HashSet.h>
     31 #import <wtf/StdLibExtras.h>
     32 
     33 namespace WebCore {
     34 
     35 static bool didReadThreadViolationBehaviorFromUserDefaults = false;
     36 static bool threadViolationBehaviorIsDefault = true;
     37 static ThreadViolationBehavior threadViolationBehavior[MaximumThreadViolationRound] = { RaiseExceptionOnThreadViolation, RaiseExceptionOnThreadViolation };
     38 
     39 static void readThreadViolationBehaviorFromUserDefaults()
     40 {
     41     didReadThreadViolationBehaviorFromUserDefaults = true;
     42 
     43     ThreadViolationBehavior newBehavior = LogOnFirstThreadViolation;
     44     NSString *threadCheckLevel = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebCoreThreadCheck"];
     45     if (!threadCheckLevel)
     46         return;
     47 
     48     if ([threadCheckLevel isEqualToString:@"None"])
     49         newBehavior = NoThreadCheck;
     50     else if ([threadCheckLevel isEqualToString:@"Exception"])
     51         newBehavior = RaiseExceptionOnThreadViolation;
     52     else if ([threadCheckLevel isEqualToString:@"Log"])
     53         newBehavior = LogOnThreadViolation;
     54     else if ([threadCheckLevel isEqualToString:@"LogOnce"])
     55         newBehavior = LogOnFirstThreadViolation;
     56     else
     57         ASSERT_NOT_REACHED();
     58 
     59     threadViolationBehaviorIsDefault = false;
     60 
     61     for (unsigned i = 0; i < MaximumThreadViolationRound; ++i)
     62         threadViolationBehavior[i] = newBehavior;
     63 }
     64 
     65 void setDefaultThreadViolationBehavior(ThreadViolationBehavior behavior, ThreadViolationRound round)
     66 {
     67     ASSERT(round < MaximumThreadViolationRound);
     68     if (round >= MaximumThreadViolationRound)
     69         return;
     70     if (!didReadThreadViolationBehaviorFromUserDefaults)
     71         readThreadViolationBehaviorFromUserDefaults();
     72     if (threadViolationBehaviorIsDefault)
     73         threadViolationBehavior[round] = behavior;
     74 }
     75 
     76 void reportThreadViolation(const char* function, ThreadViolationRound round)
     77 {
     78     ASSERT(round < MaximumThreadViolationRound);
     79     if (round >= MaximumThreadViolationRound)
     80         return;
     81     if (!didReadThreadViolationBehaviorFromUserDefaults)
     82         readThreadViolationBehaviorFromUserDefaults();
     83     if (threadViolationBehavior[round] == NoThreadCheck)
     84         return;
     85     if (pthread_main_np())
     86         return;
     87     WebCoreReportThreadViolation(function, round);
     88 }
     89 
     90 } // namespace WebCore
     91 
     92 // Split out the actual reporting of the thread violation to make it easier to set a breakpoint
     93 void WebCoreReportThreadViolation(const char* function, WebCore::ThreadViolationRound round)
     94 {
     95     using namespace WebCore;
     96 
     97     ASSERT(round < MaximumThreadViolationRound);
     98     if (round >= MaximumThreadViolationRound)
     99         return;
    100 
    101     DEFINE_STATIC_LOCAL(HashSet<String>, loggedFunctions, ());
    102     switch (threadViolationBehavior[round]) {
    103         case NoThreadCheck:
    104             break;
    105         case LogOnFirstThreadViolation:
    106             if (loggedFunctions.add(function).second) {
    107                 NSLog(@"WebKit Threading Violation - %s called from secondary thread", function);
    108                 NSLog(@"Additional threading violations for this function will not be logged.");
    109             }
    110             break;
    111         case LogOnThreadViolation:
    112             NSLog(@"WebKit Threading Violation - %s called from secondary thread", function);
    113             break;
    114         case RaiseExceptionOnThreadViolation:
    115             [NSException raise:@"WebKitThreadingException" format:@"%s was called from a secondary thread", function];
    116             break;
    117     }
    118 }
    119