ipc/chromium/src/third_party/libevent/evthread.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*
     2  * Copyright (c) 2008-2012 Niels Provos, Nick Mathewson
     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  * 3. The name of the author may not be used to endorse or promote products
    13  *    derived from this software without specific prior written permission.
    14  *
    15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    25  */
    27 #include "event2/event-config.h"
    29 #ifndef _EVENT_DISABLE_THREAD_SUPPORT
    31 #include "event2/thread.h"
    33 #include <stdlib.h>
    34 #include <string.h>
    36 #include "log-internal.h"
    37 #include "mm-internal.h"
    38 #include "util-internal.h"
    39 #include "evthread-internal.h"
    41 #ifdef EVTHREAD_EXPOSE_STRUCTS
    42 #define GLOBAL
    43 #else
    44 #define GLOBAL static
    45 #endif
    47 /* globals */
    48 GLOBAL int _evthread_lock_debugging_enabled = 0;
    49 GLOBAL struct evthread_lock_callbacks _evthread_lock_fns = {
    50 	0, 0, NULL, NULL, NULL, NULL
    51 };
    52 GLOBAL unsigned long (*_evthread_id_fn)(void) = NULL;
    53 GLOBAL struct evthread_condition_callbacks _evthread_cond_fns = {
    54 	0, NULL, NULL, NULL, NULL
    55 };
    57 /* Used for debugging */
    58 static struct evthread_lock_callbacks _original_lock_fns = {
    59 	0, 0, NULL, NULL, NULL, NULL
    60 };
    61 static struct evthread_condition_callbacks _original_cond_fns = {
    62 	0, NULL, NULL, NULL, NULL
    63 };
    65 void
    66 evthread_set_id_callback(unsigned long (*id_fn)(void))
    67 {
    68 	_evthread_id_fn = id_fn;
    69 }
    71 int
    72 evthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs)
    73 {
    74 	struct evthread_lock_callbacks *target =
    75 	    _evthread_lock_debugging_enabled
    76 	    ? &_original_lock_fns : &_evthread_lock_fns;
    78 	if (!cbs) {
    79 		if (target->alloc)
    80 			event_warnx("Trying to disable lock functions after "
    81 			    "they have been set up will probaby not work.");
    82 		memset(target, 0, sizeof(_evthread_lock_fns));
    83 		return 0;
    84 	}
    85 	if (target->alloc) {
    86 		/* Uh oh; we already had locking callbacks set up.*/
    87 		if (target->lock_api_version == cbs->lock_api_version &&
    88 			target->supported_locktypes == cbs->supported_locktypes &&
    89 			target->alloc == cbs->alloc &&
    90 			target->free == cbs->free &&
    91 			target->lock == cbs->lock &&
    92 			target->unlock == cbs->unlock) {
    93 			/* no change -- allow this. */
    94 			return 0;
    95 		}
    96 		event_warnx("Can't change lock callbacks once they have been "
    97 		    "initialized.");
    98 		return -1;
    99 	}
   100 	if (cbs->alloc && cbs->free && cbs->lock && cbs->unlock) {
   101 		memcpy(target, cbs, sizeof(_evthread_lock_fns));
   102 		return event_global_setup_locks_(1);
   103 	} else {
   104 		return -1;
   105 	}
   106 }
   108 int
   109 evthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs)
   110 {
   111 	struct evthread_condition_callbacks *target =
   112 	    _evthread_lock_debugging_enabled
   113 	    ? &_original_cond_fns : &_evthread_cond_fns;
   115 	if (!cbs) {
   116 		if (target->alloc_condition)
   117 			event_warnx("Trying to disable condition functions "
   118 			    "after they have been set up will probaby not "
   119 			    "work.");
   120 		memset(target, 0, sizeof(_evthread_cond_fns));
   121 		return 0;
   122 	}
   123 	if (target->alloc_condition) {
   124 		/* Uh oh; we already had condition callbacks set up.*/
   125 		if (target->condition_api_version == cbs->condition_api_version &&
   126 			target->alloc_condition == cbs->alloc_condition &&
   127 			target->free_condition == cbs->free_condition &&
   128 			target->signal_condition == cbs->signal_condition &&
   129 			target->wait_condition == cbs->wait_condition) {
   130 			/* no change -- allow this. */
   131 			return 0;
   132 		}
   133 		event_warnx("Can't change condition callbacks once they "
   134 		    "have been initialized.");
   135 		return -1;
   136 	}
   137 	if (cbs->alloc_condition && cbs->free_condition &&
   138 	    cbs->signal_condition && cbs->wait_condition) {
   139 		memcpy(target, cbs, sizeof(_evthread_cond_fns));
   140 	}
   141 	if (_evthread_lock_debugging_enabled) {
   142 		_evthread_cond_fns.alloc_condition = cbs->alloc_condition;
   143 		_evthread_cond_fns.free_condition = cbs->free_condition;
   144 		_evthread_cond_fns.signal_condition = cbs->signal_condition;
   145 	}
   146 	return 0;
   147 }
   149 struct debug_lock {
   150 	unsigned locktype;
   151 	unsigned long held_by;
   152 	/* XXXX if we ever use read-write locks, we will need a separate
   153 	 * lock to protect count. */
   154 	int count;
   155 	void *lock;
   156 };
   158 static void *
   159 debug_lock_alloc(unsigned locktype)
   160 {
   161 	struct debug_lock *result = mm_malloc(sizeof(struct debug_lock));
   162 	if (!result)
   163 		return NULL;
   164 	if (_original_lock_fns.alloc) {
   165 		if (!(result->lock = _original_lock_fns.alloc(
   166 				locktype|EVTHREAD_LOCKTYPE_RECURSIVE))) {
   167 			mm_free(result);
   168 			return NULL;
   169 		}
   170 	} else {
   171 		result->lock = NULL;
   172 	}
   173 	result->locktype = locktype;
   174 	result->count = 0;
   175 	result->held_by = 0;
   176 	return result;
   177 }
   179 static void
   180 debug_lock_free(void *lock_, unsigned locktype)
   181 {
   182 	struct debug_lock *lock = lock_;
   183 	EVUTIL_ASSERT(lock->count == 0);
   184 	EVUTIL_ASSERT(locktype == lock->locktype);
   185 	if (_original_lock_fns.free) {
   186 		_original_lock_fns.free(lock->lock,
   187 		    lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
   188 	}
   189 	lock->lock = NULL;
   190 	lock->count = -100;
   191 	mm_free(lock);
   192 }
   194 static void
   195 evthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock)
   196 {
   197 	++lock->count;
   198 	if (!(lock->locktype & EVTHREAD_LOCKTYPE_RECURSIVE))
   199 		EVUTIL_ASSERT(lock->count == 1);
   200 	if (_evthread_id_fn) {
   201 		unsigned long me;
   202 		me = _evthread_id_fn();
   203 		if (lock->count > 1)
   204 			EVUTIL_ASSERT(lock->held_by == me);
   205 		lock->held_by = me;
   206 	}
   207 }
   209 static int
   210 debug_lock_lock(unsigned mode, void *lock_)
   211 {
   212 	struct debug_lock *lock = lock_;
   213 	int res = 0;
   214 	if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
   215 		EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
   216 	else
   217 		EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
   218 	if (_original_lock_fns.lock)
   219 		res = _original_lock_fns.lock(mode, lock->lock);
   220 	if (!res) {
   221 		evthread_debug_lock_mark_locked(mode, lock);
   222 	}
   223 	return res;
   224 }
   226 static void
   227 evthread_debug_lock_mark_unlocked(unsigned mode, struct debug_lock *lock)
   228 {
   229 	if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
   230 		EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
   231 	else
   232 		EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
   233 	if (_evthread_id_fn) {
   234 		EVUTIL_ASSERT(lock->held_by == _evthread_id_fn());
   235 		if (lock->count == 1)
   236 			lock->held_by = 0;
   237 	}
   238 	--lock->count;
   239 	EVUTIL_ASSERT(lock->count >= 0);
   240 }
   242 static int
   243 debug_lock_unlock(unsigned mode, void *lock_)
   244 {
   245 	struct debug_lock *lock = lock_;
   246 	int res = 0;
   247 	evthread_debug_lock_mark_unlocked(mode, lock);
   248 	if (_original_lock_fns.unlock)
   249 		res = _original_lock_fns.unlock(mode, lock->lock);
   250 	return res;
   251 }
   253 static int
   254 debug_cond_wait(void *_cond, void *_lock, const struct timeval *tv)
   255 {
   256 	int r;
   257 	struct debug_lock *lock = _lock;
   258 	EVUTIL_ASSERT(lock);
   259 	EVLOCK_ASSERT_LOCKED(_lock);
   260 	evthread_debug_lock_mark_unlocked(0, lock);
   261 	r = _original_cond_fns.wait_condition(_cond, lock->lock, tv);
   262 	evthread_debug_lock_mark_locked(0, lock);
   263 	return r;
   264 }
   266 void
   267 evthread_enable_lock_debuging(void)
   268 {
   269 	struct evthread_lock_callbacks cbs = {
   270 		EVTHREAD_LOCK_API_VERSION,
   271 		EVTHREAD_LOCKTYPE_RECURSIVE,
   272 		debug_lock_alloc,
   273 		debug_lock_free,
   274 		debug_lock_lock,
   275 		debug_lock_unlock
   276 	};
   277 	if (_evthread_lock_debugging_enabled)
   278 		return;
   279 	memcpy(&_original_lock_fns, &_evthread_lock_fns,
   280 	    sizeof(struct evthread_lock_callbacks));
   281 	memcpy(&_evthread_lock_fns, &cbs,
   282 	    sizeof(struct evthread_lock_callbacks));
   284 	memcpy(&_original_cond_fns, &_evthread_cond_fns,
   285 	    sizeof(struct evthread_condition_callbacks));
   286 	_evthread_cond_fns.wait_condition = debug_cond_wait;
   287 	_evthread_lock_debugging_enabled = 1;
   289 	/* XXX return value should get checked. */
   290 	event_global_setup_locks_(0);
   291 }
   293 int
   294 _evthread_is_debug_lock_held(void *lock_)
   295 {
   296 	struct debug_lock *lock = lock_;
   297 	if (! lock->count)
   298 		return 0;
   299 	if (_evthread_id_fn) {
   300 		unsigned long me = _evthread_id_fn();
   301 		if (lock->held_by != me)
   302 			return 0;
   303 	}
   304 	return 1;
   305 }
   307 void *
   308 _evthread_debug_get_real_lock(void *lock_)
   309 {
   310 	struct debug_lock *lock = lock_;
   311 	return lock->lock;
   312 }
   314 void *
   315 evthread_setup_global_lock_(void *lock_, unsigned locktype, int enable_locks)
   316 {
   317 	/* there are four cases here:
   318 	   1) we're turning on debugging; locking is not on.
   319 	   2) we're turning on debugging; locking is on.
   320 	   3) we're turning on locking; debugging is not on.
   321 	   4) we're turning on locking; debugging is on. */
   323 	if (!enable_locks && _original_lock_fns.alloc == NULL) {
   324 		/* Case 1: allocate a debug lock. */
   325 		EVUTIL_ASSERT(lock_ == NULL);
   326 		return debug_lock_alloc(locktype);
   327 	} else if (!enable_locks && _original_lock_fns.alloc != NULL) {
   328 		/* Case 2: wrap the lock in a debug lock. */
   329 		struct debug_lock *lock;
   330 		EVUTIL_ASSERT(lock_ != NULL);
   332 		if (!(locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) {
   333 			/* We can't wrap it: We need a recursive lock */
   334 			_original_lock_fns.free(lock_, locktype);
   335 			return debug_lock_alloc(locktype);
   336 		}
   337 		lock = mm_malloc(sizeof(struct debug_lock));
   338 		if (!lock) {
   339 			_original_lock_fns.free(lock_, locktype);
   340 			return NULL;
   341 		}
   342 		lock->lock = lock_;
   343 		lock->locktype = locktype;
   344 		lock->count = 0;
   345 		lock->held_by = 0;
   346 		return lock;
   347 	} else if (enable_locks && ! _evthread_lock_debugging_enabled) {
   348 		/* Case 3: allocate a regular lock */
   349 		EVUTIL_ASSERT(lock_ == NULL);
   350 		return _evthread_lock_fns.alloc(locktype);
   351 	} else {
   352 		/* Case 4: Fill in a debug lock with a real lock */
   353 		struct debug_lock *lock = lock_;
   354 		EVUTIL_ASSERT(enable_locks &&
   355 		              _evthread_lock_debugging_enabled);
   356 		EVUTIL_ASSERT(lock->locktype == locktype);
   357 		EVUTIL_ASSERT(lock->lock == NULL);
   358 		lock->lock = _original_lock_fns.alloc(
   359 			locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
   360 		if (!lock->lock) {
   361 			lock->count = -200;
   362 			mm_free(lock);
   363 			return NULL;
   364 		}
   365 		return lock;
   366 	}
   367 }
   370 #ifndef EVTHREAD_EXPOSE_STRUCTS
   371 unsigned long
   372 _evthreadimpl_get_id()
   373 {
   374 	return _evthread_id_fn ? _evthread_id_fn() : 1;
   375 }
   376 void *
   377 _evthreadimpl_lock_alloc(unsigned locktype)
   378 {
   379 	return _evthread_lock_fns.alloc ?
   380 	    _evthread_lock_fns.alloc(locktype) : NULL;
   381 }
   382 void
   383 _evthreadimpl_lock_free(void *lock, unsigned locktype)
   384 {
   385 	if (_evthread_lock_fns.free)
   386 		_evthread_lock_fns.free(lock, locktype);
   387 }
   388 int
   389 _evthreadimpl_lock_lock(unsigned mode, void *lock)
   390 {
   391 	if (_evthread_lock_fns.lock)
   392 		return _evthread_lock_fns.lock(mode, lock);
   393 	else
   394 		return 0;
   395 }
   396 int
   397 _evthreadimpl_lock_unlock(unsigned mode, void *lock)
   398 {
   399 	if (_evthread_lock_fns.unlock)
   400 		return _evthread_lock_fns.unlock(mode, lock);
   401 	else
   402 		return 0;
   403 }
   404 void *
   405 _evthreadimpl_cond_alloc(unsigned condtype)
   406 {
   407 	return _evthread_cond_fns.alloc_condition ?
   408 	    _evthread_cond_fns.alloc_condition(condtype) : NULL;
   409 }
   410 void
   411 _evthreadimpl_cond_free(void *cond)
   412 {
   413 	if (_evthread_cond_fns.free_condition)
   414 		_evthread_cond_fns.free_condition(cond);
   415 }
   416 int
   417 _evthreadimpl_cond_signal(void *cond, int broadcast)
   418 {
   419 	if (_evthread_cond_fns.signal_condition)
   420 		return _evthread_cond_fns.signal_condition(cond, broadcast);
   421 	else
   422 		return 0;
   423 }
   424 int
   425 _evthreadimpl_cond_wait(void *cond, void *lock, const struct timeval *tv)
   426 {
   427 	if (_evthread_cond_fns.wait_condition)
   428 		return _evthread_cond_fns.wait_condition(cond, lock, tv);
   429 	else
   430 		return 0;
   431 }
   432 int
   433 _evthreadimpl_is_lock_debugging_enabled(void)
   434 {
   435 	return _evthread_lock_debugging_enabled;
   436 }
   438 int
   439 _evthreadimpl_locking_enabled(void)
   440 {
   441 	return _evthread_lock_fns.lock != NULL;
   442 }
   443 #endif
   445 #endif

mercurial