File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / threading / mutex.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:20:08 2021 UTC (3 years, 5 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, HEAD
strongswan 5.9.2

    1: /*
    2:  * Copyright (C) 2008-2012 Tobias Brunner
    3:  * Copyright (C) 2008 Martin Willi
    4:  * HSR Hochschule fuer Technik Rapperswil
    5:  *
    6:  * This program is free software; you can redistribute it and/or modify it
    7:  * under the terms of the GNU General Public License as published by the
    8:  * Free Software Foundation; either version 2 of the License, or (at your
    9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
   10:  *
   11:  * This program is distributed in the hope that it will be useful, but
   12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14:  * for more details.
   15:  */
   16: 
   17: #define _GNU_SOURCE
   18: #include <pthread.h>
   19: #include <stdint.h>
   20: #include <time.h>
   21: #include <errno.h>
   22: 
   23: #include <library.h>
   24: #include <utils/debug.h>
   25: 
   26: #include "thread.h"
   27: #include "condvar.h"
   28: #include "mutex.h"
   29: #include "lock_profiler.h"
   30: 
   31: typedef struct private_mutex_t private_mutex_t;
   32: typedef struct private_r_mutex_t private_r_mutex_t;
   33: typedef struct private_condvar_t private_condvar_t;
   34: 
   35: /**
   36:  * private data of mutex
   37:  */
   38: struct private_mutex_t {
   39: 
   40: 	/**
   41: 	 * public functions
   42: 	 */
   43: 	mutex_t public;
   44: 
   45: 	/**
   46: 	 * wrapped pthread mutex
   47: 	 */
   48: 	pthread_mutex_t mutex;
   49: 
   50: 	/**
   51: 	 * is this a recursive mutex, implementing private_r_mutex_t?
   52: 	 */
   53: 	bool recursive;
   54: 
   55: 	/**
   56: 	 * profiling info, if enabled
   57: 	 */
   58: 	lock_profile_t profile;
   59: };
   60: 
   61: /**
   62:  * private data of mutex, extended by recursive locking information
   63:  */
   64: struct private_r_mutex_t {
   65: 
   66: 	/**
   67: 	 * Extends private_mutex_t
   68: 	 */
   69: 	private_mutex_t generic;
   70: 
   71: 	/**
   72: 	 * thread which currently owns mutex
   73: 	 */
   74: 	thread_t *thread;
   75: 
   76: 	/**
   77: 	 * times the current thread locked the mutex
   78: 	 */
   79: 	u_int times;
   80: };
   81: 
   82: /**
   83:  * private data of condvar
   84:  */
   85: struct private_condvar_t {
   86: 
   87: 	/**
   88: 	 * public functions
   89: 	 */
   90: 	condvar_t public;
   91: 
   92: 	/**
   93: 	 * wrapped pthread condvar
   94: 	 */
   95: 	pthread_cond_t condvar;
   96: 
   97: };
   98: 
   99: 
  100: METHOD(mutex_t, lock, void,
  101: 	private_mutex_t *this)
  102: {
  103: 	int err;
  104: 
  105: 	profiler_start(&this->profile);
  106: 	err = pthread_mutex_lock(&this->mutex);
  107: 	if (err)
  108: 	{
  109: 		DBG1(DBG_LIB, "!!! MUTEX LOCK ERROR: %s !!!", strerror(err));
  110: 	}
  111: 	profiler_end(&this->profile);
  112: }
  113: 
  114: METHOD(mutex_t, unlock, void,
  115: 	private_mutex_t *this)
  116: {
  117: 	int err;
  118: 
  119: 	err = pthread_mutex_unlock(&this->mutex);
  120: 	if (err)
  121: 	{
  122: 		DBG1(DBG_LIB, "!!! MUTEX UNLOCK ERROR: %s !!!", strerror(err));
  123: 	}
  124: }
  125: 
  126: METHOD(mutex_t, lock_r, void,
  127: 	private_r_mutex_t *this)
  128: {
  129: 	thread_t *self = thread_current();
  130: 
  131: 	if (cas_ptr(&this->thread, self, self))
  132: 	{
  133: 		this->times++;
  134: 	}
  135: 	else
  136: 	{
  137: 		lock(&this->generic);
  138: 		cas_ptr(&this->thread, NULL, self);
  139: 		this->times = 1;
  140: 	}
  141: }
  142: 
  143: METHOD(mutex_t, unlock_r, void,
  144: 	private_r_mutex_t *this)
  145: {
  146: 	if (--this->times == 0)
  147: 	{
  148: 		cas_ptr(&this->thread, thread_current(), NULL);
  149: 		unlock(&this->generic);
  150: 	}
  151: }
  152: 
  153: METHOD(mutex_t, mutex_destroy, void,
  154: 	private_mutex_t *this)
  155: {
  156: 	profiler_cleanup(&this->profile);
  157: 	pthread_mutex_destroy(&this->mutex);
  158: 	free(this);
  159: }
  160: 
  161: METHOD(mutex_t, mutex_destroy_r, void,
  162: 	private_r_mutex_t *this)
  163: {
  164: 	profiler_cleanup(&this->generic.profile);
  165: 	pthread_mutex_destroy(&this->generic.mutex);
  166: 	free(this);
  167: }
  168: 
  169: /*
  170:  * see header file
  171:  */
  172: mutex_t *mutex_create(mutex_type_t type)
  173: {
  174: 	switch (type)
  175: 	{
  176: 		case MUTEX_TYPE_RECURSIVE:
  177: 		{
  178: 			private_r_mutex_t *this;
  179: 
  180: 			INIT(this,
  181: 				.generic = {
  182: 					.public = {
  183: 						.lock = _lock_r,
  184: 						.unlock = _unlock_r,
  185: 						.destroy = _mutex_destroy_r,
  186: 					},
  187: 					.recursive = TRUE,
  188: 				},
  189: 			);
  190: 
  191: 			pthread_mutex_init(&this->generic.mutex, NULL);
  192: 			profiler_init(&this->generic.profile);
  193: 
  194: 			return &this->generic.public;
  195: 		}
  196: 		case MUTEX_TYPE_DEFAULT:
  197: 		default:
  198: 		{
  199: 			private_mutex_t *this;
  200: 
  201: 			INIT(this,
  202: 				.public = {
  203: 					.lock = _lock,
  204: 					.unlock = _unlock,
  205: 					.destroy = _mutex_destroy,
  206: 				},
  207: 			);
  208: 
  209: 			pthread_mutex_init(&this->mutex, NULL);
  210: 			profiler_init(&this->profile);
  211: 
  212: 			return &this->public;
  213: 		}
  214: 	}
  215: }
  216: 
  217: 
  218: METHOD(condvar_t, wait_, void,
  219: 	private_condvar_t *this, private_mutex_t *mutex)
  220: {
  221: 	if (mutex->recursive)
  222: 	{
  223: 		private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
  224: 		thread_t *self = thread_current();
  225: 		u_int times;
  226: 
  227: 		/* keep track of the number of times this thread locked the mutex */
  228: 		times = recursive->times;
  229: 		/* mutex owner gets cleared during condvar wait */
  230: 		cas_ptr(&recursive->thread, self, NULL);
  231: 		pthread_cond_wait(&this->condvar, &mutex->mutex);
  232: 		cas_ptr(&recursive->thread, NULL, self);
  233: 		recursive->times = times;
  234: 	}
  235: 	else
  236: 	{
  237: 		pthread_cond_wait(&this->condvar, &mutex->mutex);
  238: 	}
  239: }
  240: 
  241: /* use the monotonic clock based version of this function if available */
  242: #if defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) && \
  243: 	!defined(HAVE_CONDATTR_CLOCK_MONOTONIC)
  244: #define pthread_cond_timedwait pthread_cond_timedwait_monotonic
  245: #endif
  246: 
  247: METHOD(condvar_t, timed_wait_abs, bool,
  248: 	private_condvar_t *this, private_mutex_t *mutex, timeval_t time)
  249: {
  250: 	struct timespec ts;
  251: 	bool timed_out;
  252: 
  253: 	ts.tv_sec = time.tv_sec;
  254: 	ts.tv_nsec = time.tv_usec * 1000;
  255: 
  256: 	if (mutex->recursive)
  257: 	{
  258: 		private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
  259: 		thread_t *self = thread_current();
  260: 		u_int times;
  261: 
  262: 		times = recursive->times;
  263: 		cas_ptr(&recursive->thread, self, NULL);
  264: 		timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex,
  265: 										   &ts) == ETIMEDOUT;
  266: 		cas_ptr(&recursive->thread, NULL, self);
  267: 		recursive->times = times;
  268: 	}
  269: 	else
  270: 	{
  271: 		timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex,
  272: 										   &ts) == ETIMEDOUT;
  273: 	}
  274: 	return timed_out;
  275: }
  276: 
  277: METHOD(condvar_t, timed_wait, bool,
  278: 	private_condvar_t *this, private_mutex_t *mutex, u_int timeout)
  279: {
  280: 	timeval_t tv;
  281: 	u_int s, ms;
  282: 
  283: 	time_monotonic(&tv);
  284: 
  285: 	s = timeout / 1000;
  286: 	ms = timeout % 1000;
  287: 
  288: 	tv.tv_sec += s;
  289: 	timeval_add_ms(&tv, ms);
  290: 	return timed_wait_abs(this, mutex, tv);
  291: }
  292: 
  293: METHOD(condvar_t, signal_, void,
  294: 	private_condvar_t *this)
  295: {
  296: 	pthread_cond_signal(&this->condvar);
  297: }
  298: 
  299: METHOD(condvar_t, broadcast, void,
  300: 	private_condvar_t *this)
  301: {
  302: 	pthread_cond_broadcast(&this->condvar);
  303: }
  304: 
  305: METHOD(condvar_t, condvar_destroy, void,
  306: 	private_condvar_t *this)
  307: {
  308: 	pthread_cond_destroy(&this->condvar);
  309: 	free(this);
  310: }
  311: 
  312: /*
  313:  * see header file
  314:  */
  315: condvar_t *condvar_create(condvar_type_t type)
  316: {
  317: 	switch (type)
  318: 	{
  319: 		case CONDVAR_TYPE_DEFAULT:
  320: 		default:
  321: 		{
  322: 			private_condvar_t *this;
  323: 
  324: 			INIT(this,
  325: 				.public = {
  326: 					.wait = (void*)_wait_,
  327: 					.timed_wait = (void*)_timed_wait,
  328: 					.timed_wait_abs = (void*)_timed_wait_abs,
  329: 					.signal = _signal_,
  330: 					.broadcast = _broadcast,
  331: 					.destroy = _condvar_destroy,
  332: 				}
  333: 			);
  334: 
  335: #ifdef HAVE_PTHREAD_CONDATTR_INIT
  336: 			{
  337: 				pthread_condattr_t condattr;
  338: 				pthread_condattr_init(&condattr);
  339: #ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
  340: 				pthread_condattr_setclock(&condattr, TIME_CLOCK_ID);
  341: #endif
  342: 				pthread_cond_init(&this->condvar, &condattr);
  343: 				pthread_condattr_destroy(&condattr);
  344: 			}
  345: #endif
  346: 
  347: 			return &this->public;
  348: 		}
  349: 	}
  350: }
  351: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>