xref: /aosp_15_r20/external/cronet/third_party/apache-portable-runtime/src/locks/win32/thread_cond.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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