1: /*
2: * Copyright (C) 2011 Tobias Brunner
3: * HSR Hochschule fuer Technik Rapperswil
4: *
5: * This program is free software; you can redistribute it and/or modify it
6: * under the terms of the GNU General Public License as published by the
7: * Free Software Foundation; either version 2 of the License, or (at your
8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9: *
10: * This program is distributed in the hope that it will be useful, but
11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13: * for more details.
14: */
15:
16: #include <library.h>
17:
18: #if defined(HAVE_CLOCK_GETTIME) && \
19: (defined(HAVE_CONDATTR_CLOCK_MONOTONIC) || \
20: defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
21: /* if we use MONOTONIC times, we can't use POSIX_SEMAPHORES since they use
22: * times based on CLOCK_REALTIME */
23: #undef HAVE_SEM_TIMEDWAIT
24: #endif /* HAVE_CLOCK_GETTIME && ... */
25:
26: #ifdef HAVE_SEM_TIMEDWAIT
27: #include <semaphore.h>
28: #else /* !HAVE_SEM_TIMEDWAIT */
29: #include <threading/thread.h>
30: #include <threading/condvar.h>
31: #endif /* HAVE_SEM_TIMEDWAIT */
32:
33: #include "semaphore.h"
34:
35: typedef struct private_semaphore_t private_semaphore_t;
36:
37: /**
38: * private data of a semaphore
39: */
40: struct private_semaphore_t {
41: /**
42: * public interface
43: */
44: semaphore_t public;
45:
46: #ifdef HAVE_SEM_TIMEDWAIT
47: /**
48: * wrapped POSIX semaphore object
49: */
50: sem_t sem;
51: #else /* !HAVE_SEM_TIMEDWAIT */
52:
53: /**
54: * Mutex to lock count variable
55: */
56: mutex_t *mutex;
57:
58: /**
59: * Condvar to signal count increase
60: */
61: condvar_t *cond;
62:
63: /**
64: * Semaphore count value
65: */
66: u_int count;
67: #endif /* HAVE_SEM_TIMEDWAIT */
68: };
69:
70: METHOD(semaphore_t, wait_, void,
71: private_semaphore_t *this)
72: {
73: #ifdef HAVE_SEM_TIMEDWAIT
74: sem_wait(&this->sem);
75: #else /* !HAVE_SEM_TIMEDWAIT */
76: this->mutex->lock(this->mutex);
77: thread_cleanup_push((void*)this->mutex->unlock, this->mutex);
78: while (this->count == 0)
79: {
80: this->cond->wait(this->cond, this->mutex);
81: }
82: this->count--;
83: thread_cleanup_pop(TRUE);
84: #endif /* HAVE_SEM_TIMEDWAIT */
85: }
86:
87: METHOD(semaphore_t, timed_wait_abs, bool,
88: private_semaphore_t *this, timeval_t tv)
89: {
90: #ifdef HAVE_SEM_TIMEDWAIT
91: timespec_t ts;
92:
93: ts.tv_sec = tv.tv_sec;
94: ts.tv_nsec = tv.tv_usec * 1000;
95:
96: /* there are errors other than ETIMEDOUT possible, but we consider them
97: * all as timeout */
98: return sem_timedwait(&this->sem, &ts) == -1;
99: #else /* !HAVE_SEM_TIMEDWAIT */
100: this->mutex->lock(this->mutex);
101: thread_cleanup_push((void*)this->mutex->unlock, this->mutex);
102: while (this->count == 0)
103: {
104: if (this->cond->timed_wait_abs(this->cond, this->mutex, tv))
105: {
106: thread_cleanup_pop(TRUE);
107: return TRUE;
108: }
109: }
110: this->count--;
111: thread_cleanup_pop(TRUE);
112: return FALSE;
113: #endif /* HAVE_SEM_TIMEDWAIT */
114: }
115:
116: METHOD(semaphore_t, timed_wait, bool,
117: private_semaphore_t *this, u_int timeout)
118: {
119: timeval_t tv, add;
120:
121: add.tv_sec = timeout / 1000;
122: add.tv_usec = (timeout % 1000) * 1000;
123:
124: time_monotonic(&tv);
125: timeradd(&tv, &add, &tv);
126:
127: return timed_wait_abs(this, tv);
128: }
129:
130: METHOD(semaphore_t, post, void,
131: private_semaphore_t *this)
132: {
133: #ifdef HAVE_SEM_TIMEDWAIT
134: sem_post(&this->sem);
135: #else /* !HAVE_SEM_TIMEDWAIT */
136: this->mutex->lock(this->mutex);
137: this->count++;
138: this->mutex->unlock(this->mutex);
139: this->cond->signal(this->cond);
140: #endif /* HAVE_SEM_TIMEDWAIT */
141: }
142:
143: METHOD(semaphore_t, destroy, void,
144: private_semaphore_t *this)
145: {
146: #ifdef HAVE_SEM_TIMEDWAIT
147: sem_destroy(&this->sem);
148: #else /* !HAVE_SEM_TIMEDWAIT */
149: this->cond->destroy(this->cond);
150: this->mutex->destroy(this->mutex);
151: #endif /* HAVE_SEM_TIMEDWAIT */
152: free(this);
153: }
154:
155: /*
156: * Described in header
157: */
158: semaphore_t *semaphore_create(u_int value)
159: {
160: private_semaphore_t *this;
161:
162: INIT(this,
163: .public = {
164: .wait = _wait_,
165: .timed_wait = _timed_wait,
166: .timed_wait_abs = _timed_wait_abs,
167: .post = _post,
168: .destroy = _destroy,
169: },
170: );
171:
172: #ifdef HAVE_SEM_TIMEDWAIT
173: sem_init(&this->sem, 0, value);
174: #else /* !HAVE_SEM_TIMEDWAIT */
175: this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
176: this->cond = condvar_create(CONDVAR_TYPE_DEFAULT);
177: this->count = value;
178: #endif /* HAVE_SEM_TIMEDWAIT */
179:
180: return &this->public;
181: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>