Separated the public interfaces of the threading primitives.
[strongswan.git] / src / libstrongswan / threading / condvar.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 #include <stdint.h>
20 #include <time.h>
21 #include <errno.h>
22
23 #include <library.h>
24 #include <debug.h>
25
26 #include "condvar.h"
27 #include "mutex.h"
28
29 typedef struct private_condvar_t private_condvar_t;
30
31 /**
32 * private data of condvar
33 */
34 struct private_condvar_t {
35
36 /**
37 * public functions
38 */
39 condvar_t public;
40
41 /**
42 * wrapped pthread condvar
43 */
44 pthread_cond_t condvar;
45 };
46
47 /**
48 * Implementation of condvar_t.wait.
49 */
50 static void _wait(private_condvar_t *this, private_mutex_t *mutex)
51 {
52 if (mutex->recursive)
53 {
54 private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
55
56 /* mutex owner gets cleared during condvar wait */
57 recursive->thread = 0;
58 pthread_cond_wait(&this->condvar, &mutex->mutex);
59 recursive->thread = pthread_self();
60 }
61 else
62 {
63 pthread_cond_wait(&this->condvar, &mutex->mutex);
64 }
65 }
66
67 /**
68 * Implementation of condvar_t.timed_wait_abs.
69 */
70 static bool timed_wait_abs(private_condvar_t *this, private_mutex_t *mutex,
71 timeval_t time)
72 {
73 struct timespec ts;
74 bool timed_out;
75
76 ts.tv_sec = time.tv_sec;
77 ts.tv_nsec = time.tv_usec * 1000;
78
79 if (mutex->recursive)
80 {
81 private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
82
83 recursive->thread = 0;
84 timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex,
85 &ts) == ETIMEDOUT;
86 recursive->thread = pthread_self();
87 }
88 else
89 {
90 timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex,
91 &ts) == ETIMEDOUT;
92 }
93 return timed_out;
94 }
95
96 /**
97 * Implementation of condvar_t.timed_wait.
98 */
99 static bool timed_wait(private_condvar_t *this, private_mutex_t *mutex,
100 u_int timeout)
101 {
102 timeval_t tv;
103 u_int s, ms;
104
105 time_monotonic(&tv);
106
107 s = timeout / 1000;
108 ms = timeout % 1000;
109
110 tv.tv_sec += s;
111 tv.tv_usec += ms * 1000;
112
113 if (tv.tv_usec > 1000000 /* 1s */)
114 {
115 tv.tv_usec -= 1000000;
116 tv.tv_sec++;
117 }
118 return timed_wait_abs(this, mutex, tv);
119 }
120
121 /**
122 * Implementation of condvar_t.signal.
123 */
124 static void _signal(private_condvar_t *this)
125 {
126 pthread_cond_signal(&this->condvar);
127 }
128
129 /**
130 * Implementation of condvar_t.broadcast.
131 */
132 static void broadcast(private_condvar_t *this)
133 {
134 pthread_cond_broadcast(&this->condvar);
135 }
136
137 /**
138 * Implementation of condvar_t.destroy
139 */
140 static void condvar_destroy(private_condvar_t *this)
141 {
142 pthread_cond_destroy(&this->condvar);
143 free(this);
144 }
145
146 /*
147 * see header file
148 */
149 condvar_t *condvar_create(condvar_type_t type)
150 {
151 switch (type)
152 {
153 case CONDVAR_TYPE_DEFAULT:
154 default:
155 {
156 pthread_condattr_t condattr;
157 private_condvar_t *this = malloc_thing(private_condvar_t);
158
159 this->public.wait = (void(*)(condvar_t*, mutex_t *mutex))_wait;
160 this->public.timed_wait = (bool(*)(condvar_t*, mutex_t *mutex, u_int timeout))timed_wait;
161 this->public.timed_wait_abs = (bool(*)(condvar_t*, mutex_t *mutex, timeval_t time))timed_wait_abs;
162 this->public.signal = (void(*)(condvar_t*))_signal;
163 this->public.broadcast = (void(*)(condvar_t*))broadcast;
164 this->public.destroy = (void(*)(condvar_t*))condvar_destroy;
165
166 pthread_condattr_init(&condattr);
167 #ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
168 pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
169 #endif
170 pthread_cond_init(&this->condvar, &condattr);
171 pthread_condattr_destroy(&condattr);
172
173 return &this->public;
174 }
175 }
176 }
177