Threading primitives separated.
[strongswan.git] / src / libstrongswan / threading / mutex.c
1 /*
2 * Copyright (C) 2008-2009 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * 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
20 #include <threading.h>
21 #include <library.h>
22 #include <debug.h>
23
24 #include "mutex.h"
25 #include "lock_profiler.h"
26
27 /**
28 * Implementation of mutex_t.lock.
29 */
30 static void lock(private_mutex_t *this)
31 {
32 int err;
33
34 profiler_start(&this->profile);
35 err = pthread_mutex_lock(&this->mutex);
36 if (err)
37 {
38 DBG1("!!! MUTEX LOCK ERROR: %s !!!", strerror(err));
39 }
40 profiler_end(&this->profile);
41 }
42
43 /**
44 * Implementation of mutex_t.unlock.
45 */
46 static void unlock(private_mutex_t *this)
47 {
48 int err;
49
50 err = pthread_mutex_unlock(&this->mutex);
51 if (err)
52 {
53 DBG1("!!! MUTEX UNLOCK ERROR: %s !!!", strerror(err));
54 }
55 }
56
57 /**
58 * Implementation of mutex_t.lock.
59 */
60 static void lock_r(private_r_mutex_t *this)
61 {
62 pthread_t self = pthread_self();
63
64 if (this->thread == self)
65 {
66 uintptr_t times;
67
68 /* times++ */
69 times = (uintptr_t)pthread_getspecific(this->times);
70 pthread_setspecific(this->times, (void*)times + 1);
71 }
72 else
73 {
74 lock(&this->generic);
75 this->thread = self;
76 /* times = 1 */
77 pthread_setspecific(this->times, (void*)1);
78 }
79 }
80
81 /**
82 * Implementation of mutex_t.unlock.
83 */
84 static void unlock_r(private_r_mutex_t *this)
85 {
86 uintptr_t times;
87
88 /* times-- */
89 times = (uintptr_t)pthread_getspecific(this->times);
90 pthread_setspecific(this->times, (void*)--times);
91
92 if (times == 0)
93 {
94 this->thread = 0;
95 unlock(&this->generic);
96 }
97 }
98
99 /**
100 * Implementation of mutex_t.destroy
101 */
102 static void mutex_destroy(private_mutex_t *this)
103 {
104 profiler_cleanup(&this->profile);
105 pthread_mutex_destroy(&this->mutex);
106 free(this);
107 }
108
109 /**
110 * Implementation of mutex_t.destroy for recursive mutex'
111 */
112 static void mutex_destroy_r(private_r_mutex_t *this)
113 {
114 profiler_cleanup(&this->generic.profile);
115 pthread_mutex_destroy(&this->generic.mutex);
116 pthread_key_delete(this->times);
117 free(this);
118 }
119
120 /*
121 * see header file
122 */
123 mutex_t *mutex_create(mutex_type_t type)
124 {
125 switch (type)
126 {
127 case MUTEX_TYPE_RECURSIVE:
128 {
129 private_r_mutex_t *this = malloc_thing(private_r_mutex_t);
130
131 this->generic.public.lock = (void(*)(mutex_t*))lock_r;
132 this->generic.public.unlock = (void(*)(mutex_t*))unlock_r;
133 this->generic.public.destroy = (void(*)(mutex_t*))mutex_destroy_r;
134
135 pthread_mutex_init(&this->generic.mutex, NULL);
136 pthread_key_create(&this->times, NULL);
137 this->generic.recursive = TRUE;
138 profiler_init(&this->generic.profile);
139 this->thread = 0;
140
141 return &this->generic.public;
142 }
143 case MUTEX_TYPE_DEFAULT:
144 default:
145 {
146 private_mutex_t *this = malloc_thing(private_mutex_t);
147
148 this->public.lock = (void(*)(mutex_t*))lock;
149 this->public.unlock = (void(*)(mutex_t*))unlock;
150 this->public.destroy = (void(*)(mutex_t*))mutex_destroy;
151
152 pthread_mutex_init(&this->mutex, NULL);
153 this->recursive = FALSE;
154 profiler_init(&this->profile);
155
156 return &this->public;
157 }
158 }
159 }
160