1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "apr.h"
18 #include "apr_private.h"
19 #include "apr_general.h"
20 #include "apr_strings.h"
21 #include "apr_arch_thread_mutex.h"
22 #include "apr_arch_thread_cond.h"
23 #include "apr_portable.h"
24
25 #include <limits.h>
26
thread_cond_cleanup(void * data)27 static apr_status_t thread_cond_cleanup(void *data)
28 {
29 apr_thread_cond_t *cond = data;
30 CloseHandle(cond->semaphore);
31 DeleteCriticalSection(&cond->csection);
32 return APR_SUCCESS;
33 }
34
apr_thread_cond_create(apr_thread_cond_t ** cond,apr_pool_t * pool)35 APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond,
36 apr_pool_t *pool)
37 {
38 apr_thread_cond_t *cv;
39
40 cv = apr_pcalloc(pool, sizeof(**cond));
41 if (cv == NULL) {
42 return APR_ENOMEM;
43 }
44
45 cv->semaphore = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
46 if (cv->semaphore == NULL) {
47 return apr_get_os_error();
48 }
49
50 *cond = cv;
51 cv->pool = pool;
52 InitializeCriticalSection(&cv->csection);
53 apr_pool_cleanup_register(cv->pool, cv, thread_cond_cleanup,
54 apr_pool_cleanup_null);
55
56 return APR_SUCCESS;
57 }
58
apr_thread_cond_destroy(apr_thread_cond_t * cond)59 APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond)
60 {
61 return apr_pool_cleanup_run(cond->pool, cond, thread_cond_cleanup);
62 }
63
_thread_cond_timedwait(apr_thread_cond_t * cond,apr_thread_mutex_t * mutex,DWORD timeout_ms)64 static APR_INLINE apr_status_t _thread_cond_timedwait(apr_thread_cond_t *cond,
65 apr_thread_mutex_t *mutex,
66 DWORD timeout_ms )
67 {
68 DWORD res;
69 apr_status_t rv;
70 unsigned int wake = 0;
71 unsigned long generation;
72
73 EnterCriticalSection(&cond->csection);
74 cond->num_waiting++;
75 generation = cond->generation;
76 LeaveCriticalSection(&cond->csection);
77
78 apr_thread_mutex_unlock(mutex);
79
80 do {
81 res = WaitForSingleObject(cond->semaphore, timeout_ms);
82
83 EnterCriticalSection(&cond->csection);
84
85 if (cond->num_wake) {
86 if (cond->generation != generation) {
87 cond->num_wake--;
88 cond->num_waiting--;
89 rv = APR_SUCCESS;
90 break;
91 } else {
92 wake = 1;
93 }
94 }
95 else if (res != WAIT_OBJECT_0) {
96 cond->num_waiting--;
97 rv = APR_TIMEUP;
98 break;
99 }
100
101 LeaveCriticalSection(&cond->csection);
102
103 if (wake) {
104 wake = 0;
105 ReleaseSemaphore(cond->semaphore, 1, NULL);
106 }
107 } while (1);
108
109 LeaveCriticalSection(&cond->csection);
110 apr_thread_mutex_lock(mutex);
111
112 return rv;
113 }
114
apr_thread_cond_wait(apr_thread_cond_t * cond,apr_thread_mutex_t * mutex)115 APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond,
116 apr_thread_mutex_t *mutex)
117 {
118 return _thread_cond_timedwait(cond, mutex, INFINITE);
119 }
120
apr_thread_cond_timedwait(apr_thread_cond_t * cond,apr_thread_mutex_t * mutex,apr_interval_time_t timeout)121 APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond,
122 apr_thread_mutex_t *mutex,
123 apr_interval_time_t timeout)
124 {
125 DWORD timeout_ms = (DWORD) apr_time_as_msec(timeout);
126
127 return _thread_cond_timedwait(cond, mutex, timeout_ms);
128 }
129
apr_thread_cond_signal(apr_thread_cond_t * cond)130 APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond)
131 {
132 unsigned int wake = 0;
133
134 EnterCriticalSection(&cond->csection);
135 if (cond->num_waiting > cond->num_wake) {
136 wake = 1;
137 cond->num_wake++;
138 cond->generation++;
139 }
140 LeaveCriticalSection(&cond->csection);
141
142 if (wake) {
143 ReleaseSemaphore(cond->semaphore, 1, NULL);
144 }
145
146 return APR_SUCCESS;
147 }
148
apr_thread_cond_broadcast(apr_thread_cond_t * cond)149 APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond)
150 {
151 unsigned long num_wake = 0;
152
153 EnterCriticalSection(&cond->csection);
154 if (cond->num_waiting > cond->num_wake) {
155 num_wake = cond->num_waiting - cond->num_wake;
156 cond->num_wake = cond->num_waiting;
157 cond->generation++;
158 }
159 LeaveCriticalSection(&cond->csection);
160
161 if (num_wake) {
162 ReleaseSemaphore(cond->semaphore, num_wake, NULL);
163 }
164
165 return APR_SUCCESS;
166 }
167
168 APR_POOL_IMPLEMENT_ACCESSOR(thread_cond)
169