1
/* ``The contents of this file are subject to the Erlang Public License,
2
* Version 1.1, (the "License"); you may not use this file except in
3
* compliance with the License. You should have received a copy of the
4
* Erlang Public License along with this software. If not, it can be
5
* retrieved via the world wide web at http://www.erlang.org/.
7
* Software distributed under the License is distributed on an "AS IS"
8
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
* the License for the specific language governing rights and limitations
12
* The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
* Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
* AB. All Rights Reserved.''
31
#include "erl_alloc.h"
32
#include "erl_driver.h"
33
#define ERL_THREADS_EMU_INTERNAL__
34
#include "erl_threads.h"
36
static DWORD tl_wait_ix;
37
typedef struct _erts_wait_t {
39
struct _erts_wait_t *next;
40
struct _erts_wait_t *prev;
44
typedef struct _erts_cond_t {
46
struct _erts_wait_t *waiters;
49
static _erts_wait_t main_thread_wait;
51
static CRITICAL_SECTION sys_mutex[ERTS_MAX_SYS_MUTEX];
53
erts_mutex_t erts_mutex_create()
55
CRITICAL_SECTION* mp = (CRITICAL_SECTION*)
56
erts_alloc_fnf(ERTS_ALC_T_MUTEX, sizeof(CRITICAL_SECTION));
58
InitializeCriticalSection(mp);
59
return (erts_mutex_t) mp;
62
erts_mutex_t erts_mutex_sys(int mno)
65
if (mno >= ERTS_MAX_SYS_MUTEX || mno < 0)
68
InitializeCriticalSection(mp);
69
return (erts_mutex_t) mp;
73
int erts_atfork_sys(void (*prepare)(void),
80
int erts_mutex_set_default_atfork(erts_mutex_t mtx)
85
int erts_mutex_unset_default_atfork(erts_mutex_t mtx)
90
int erts_mutex_destroy(erts_mutex_t mtx)
93
DeleteCriticalSection((CRITICAL_SECTION*)mtx);
94
erts_free(ERTS_ALC_T_MUTEX, mtx);
100
int erts_mutex_lock (erts_mutex_t mtx)
102
EnterCriticalSection((CRITICAL_SECTION*) mtx);
106
int erts_mutex_unlock (erts_mutex_t mtx)
108
LeaveCriticalSection((CRITICAL_SECTION*) mtx);
112
erts_cond_t erts_cond_create()
114
_erts_cond_t* cvp = (_erts_cond_t*)
115
erts_alloc_fnf(ERTS_ALC_T_COND_VAR, sizeof(_erts_cond_t));
116
InitializeCriticalSection(&cvp->cs);
118
return (erts_cond_t) cvp;
121
int erts_cond_destroy(erts_cond_t cv)
123
_erts_cond_t* cvp = (_erts_cond_t*) cv;
125
DeleteCriticalSection(&cvp->cs);
126
erts_free(ERTS_ALC_T_COND_VAR, cvp);
132
int erts_cond_signal(erts_cond_t cv)
134
_erts_cond_t* cvp = (_erts_cond_t*) cv;
135
EnterCriticalSection(&cvp->cs);
137
SetEvent(cvp->waiters->event);
138
cvp->waiters->in_list = 0;
139
cvp->waiters = cvp->waiters->next;
141
cvp->waiters->prev = NULL;
143
LeaveCriticalSection(&cvp->cs);
147
int erts_cond_broadcast (erts_cond_t cv)
149
struct _erts_wait_t *wp;
150
_erts_cond_t* cvp = (_erts_cond_t*) cv;
152
/* signal every event in waiting queue */
153
EnterCriticalSection(&cvp->cs);
154
for (wp = cvp->waiters; wp; wp = wp->next) {
159
LeaveCriticalSection(&cvp->cs);
163
int erts_cond_wait(erts_cond_t cv, erts_mutex_t mtx)
165
return erts_cond_timedwait(cv, mtx, INFINITE);
168
int erts_cond_timedwait(erts_cond_t cv, erts_mutex_t mtx, long time)
170
_erts_cond_t* cvp = (_erts_cond_t*) cv;
174
EnterCriticalSection(&cvp->cs);
176
wp = (_erts_wait_t *) TlsGetValue(tl_wait_ix);
180
wp->next = cvp->waiters;
185
LeaveCriticalSection(&cvp->cs);
187
/* wait for event to signal */
188
LeaveCriticalSection((CRITICAL_SECTION*) mtx);
189
code = WaitForSingleObject(wp->event, time);
190
EnterCriticalSection((CRITICAL_SECTION*)mtx);
192
if (code != WAIT_OBJECT_0) {
193
EnterCriticalSection(&cvp->cs);
195
/* remove from wait list */
197
wp->prev->next = wp->next;
199
cvp->waiters = wp->next;
201
wp->next->prev = wp->prev;
204
LeaveCriticalSection(&cvp->cs);
206
/* else: we was removed from the list by a signal or broadcast */
208
/* resume processing */
209
return code != WAIT_OBJECT_0;
214
void* (*func)(void*);
219
static unsigned thread_wrapper(void* args)
221
void* (*func)(void*);
226
func = ((thread_data__ *) args)->func;
227
arg = ((thread_data__ *) args)->arg;
228
pwait = ((thread_data__ *) args)->pwait;
230
wait.event = CreateEvent(NULL, FALSE, FALSE, NULL);
232
if (!wait.event || !TlsSetValue(tl_wait_ix, (LPVOID) &wait)) {
234
CloseHandle(wait.event);
235
((thread_data__ *) args)->res = -1;
236
SetEvent(pwait->event);
237
_endthreadex((unsigned) 1);
241
ASSERT(&wait == (_erts_wait_t *) TlsGetValue(tl_wait_ix));
242
((thread_data__ *) args)->res = 0;
243
SetEvent(pwait->event);
245
(void) /* FIXME: Implement propagation of threads result */
248
CloseHandle(wait.event);
255
int erts_thread_create(erts_thread_t* tpp,
256
void* (*func)(void*),
268
td.pwait = (_erts_wait_t *) TlsGetValue(tl_wait_ix);
271
h = (HANDLE) _beginthreadex(NULL,
273
(LPTHREAD_START_ROUTINE) thread_wrapper,
277
if (h == INVALID_HANDLE_VALUE)
279
code = WaitForSingleObject(td.pwait->event, INFINITE);
282
*tpp = (erts_thread_t)h;
283
if (code != WAIT_OBJECT_0) {
290
erts_thread_t erts_thread_self()
292
return GetCurrentThread();
295
void erts_thread_exit(void* val)
297
_erts_wait_t *wp = (_erts_wait_t *) TlsGetValue(tl_wait_ix);
298
CloseHandle(wp->event);
299
/* FIXME: Implement propagation of threads result */
303
int erts_thread_join(erts_thread_t tp, void** vp)
305
/* FIXME: Implement propagation of threads result */
307
code = WaitForSingleObject((HANDLE)tp, INFINITE); /* FIX ERRORS */
309
return code != WAIT_OBJECT_0;
312
int erts_thread_kill(erts_thread_t tp)
317
void __noreturn erl_exit(int n, char*, ...);
320
erts_sys_threads_init(void)
322
/* NOTE: erts_sys_threads_init() is called before allocators are
323
* initialized; therefore, it's not allowed to call erts_alloc()
324
* (and friends) from here.
327
tl_wait_ix = TlsAlloc();
328
if (tl_wait_ix == -1)
329
erl_exit(1, "Failed to allocate thread local wait index\n");
330
if (!TlsSetValue(tl_wait_ix, (LPVOID) &main_thread_wait))
331
erl_exit(1, "Failed to set main thread wait object\n");
332
main_thread_wait.event = CreateEvent(NULL, FALSE, FALSE, NULL);
333
main_thread_wait.in_list = 0;
334
if (!main_thread_wait.event)
335
erl_exit(1, "Failed to create main thread wait event\n");
337
ASSERT(&main_thread_wait == (_erts_wait_t *) TlsGetValue(tl_wait_ix));