1 /* thr_nt.c - wrapper around NT threads */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2021 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 
17 #include "portable.h"
18 
19 #if defined( HAVE_NT_THREADS )
20 
21 #define _WIN32_WINNT 0x0400
22 #include <windows.h>
23 #include <process.h>
24 
25 #include "ldap_pvt_thread.h" /* Get the thread interface */
26 #define LDAP_THREAD_IMPLEMENTATION
27 #include "ldap_thr_debug.h"	 /* May rename the symbols defined below */
28 
29 typedef struct ldap_int_thread_s {
30 	long tid;
31 	HANDLE thd;
32 } ldap_int_thread_s;
33 
34 #ifndef NT_MAX_THREADS
35 #define NT_MAX_THREADS	1024
36 #endif
37 
38 static ldap_int_thread_s tids[NT_MAX_THREADS];
39 static int ntids;
40 
41 
42 /* mingw compiler very sensitive about getting prototypes right */
43 typedef unsigned __stdcall thrfunc_t(void *);
44 
45 int
ldap_int_thread_initialize(void)46 ldap_int_thread_initialize( void )
47 {
48 	return 0;
49 }
50 
51 int
ldap_int_thread_destroy(void)52 ldap_int_thread_destroy( void )
53 {
54 	return 0;
55 }
56 
57 int
ldap_int_mutex_firstcreate(ldap_int_thread_mutex_t * mutex)58 ldap_int_mutex_firstcreate( ldap_int_thread_mutex_t *mutex )
59 {
60 	if ( *mutex == NULL ) {
61 		HANDLE p = CreateMutex( NULL, 0, NULL );
62 		if ( InterlockedCompareExchangePointer((PVOID*)mutex, (PVOID)p, NULL) != NULL)
63 			CloseHandle( p );
64 	}
65 	return 0;
66 }
67 
68 int
ldap_pvt_thread_create(ldap_pvt_thread_t * thread,int detach,void * (* start_routine)(void *),void * arg)69 ldap_pvt_thread_create( ldap_pvt_thread_t * thread,
70 	int detach,
71 	void *(*start_routine)( void *),
72 	void *arg)
73 {
74 	unsigned tid;
75 	HANDLE thd;
76 	int rc = -1;
77 
78 	thd = (HANDLE) _beginthreadex(NULL, LDAP_PVT_THREAD_STACK_SIZE, (thrfunc_t *) start_routine,
79 				      arg, 0, &tid);
80 
81 	if ( thd ) {
82 		*thread = (ldap_pvt_thread_t) tid;
83 		tids[ntids].tid = tid;
84 		tids[ntids].thd = thd;
85 		ntids++;
86 		rc = 0;
87 	}
88 	return rc;
89 }
90 
91 void
ldap_pvt_thread_exit(void * retval)92 ldap_pvt_thread_exit( void *retval )
93 {
94 	_endthread( );
95 }
96 
97 int
ldap_pvt_thread_join(ldap_pvt_thread_t thread,void ** thread_return)98 ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
99 {
100 	DWORD status;
101 	int i;
102 
103 	for (i=0; i<ntids; i++) {
104 		if ( tids[i].tid == thread )
105 			break;
106 	}
107 	if ( i > ntids ) return -1;
108 
109 	status = WaitForSingleObject( tids[i].thd, INFINITE );
110 	for (; i<ntids; i++) {
111 		tids[i] = tids[i+1];
112 	}
113 	ntids--;
114 	return status == WAIT_FAILED ? -1 : 0;
115 }
116 
117 int
ldap_pvt_thread_kill(ldap_pvt_thread_t thread,int signo)118 ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
119 {
120 	return 0;
121 }
122 
123 int
ldap_pvt_thread_yield(void)124 ldap_pvt_thread_yield( void )
125 {
126 	Sleep( 0 );
127 	return 0;
128 }
129 
130 int
ldap_pvt_thread_cond_init(ldap_pvt_thread_cond_t * cond)131 ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond )
132 {
133 	*cond = CreateEvent( NULL, FALSE, FALSE, NULL );
134 	return( 0 );
135 }
136 
137 int
ldap_pvt_thread_cond_destroy(ldap_pvt_thread_cond_t * cv)138 ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cv )
139 {
140 	CloseHandle( *cv );
141 	return( 0 );
142 }
143 
144 int
ldap_pvt_thread_cond_signal(ldap_pvt_thread_cond_t * cond)145 ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond )
146 {
147 	SetEvent( *cond );
148 	return( 0 );
149 }
150 
151 int
ldap_pvt_thread_cond_wait(ldap_pvt_thread_cond_t * cond,ldap_pvt_thread_mutex_t * mutex)152 ldap_pvt_thread_cond_wait( ldap_pvt_thread_cond_t *cond,
153 	ldap_pvt_thread_mutex_t *mutex )
154 {
155 	SignalObjectAndWait( *mutex, *cond, INFINITE, FALSE );
156 	WaitForSingleObject( *mutex, INFINITE );
157 	return( 0 );
158 }
159 
160 int
ldap_pvt_thread_cond_broadcast(ldap_pvt_thread_cond_t * cond)161 ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond )
162 {
163 	while ( WaitForSingleObject( *cond, 0 ) == WAIT_TIMEOUT )
164 		SetEvent( *cond );
165 	return( 0 );
166 }
167 
168 int
ldap_pvt_thread_mutex_init(ldap_pvt_thread_mutex_t * mutex)169 ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex )
170 {
171 	*mutex = CreateMutex( NULL, 0, NULL );
172 	return ( 0 );
173 }
174 
175 int
ldap_pvt_thread_mutex_recursive_init(ldap_pvt_thread_mutex_t * mutex)176 ldap_pvt_thread_mutex_recursive_init( ldap_pvt_thread_mutex_t *mutex )
177 {
178 	/* All NT mutexes are recursive */
179 	return ldap_pvt_thread_mutex_init( mutex );
180 }
181 
182 int
ldap_pvt_thread_mutex_destroy(ldap_pvt_thread_mutex_t * mutex)183 ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex )
184 {
185 	CloseHandle( *mutex );
186 	return ( 0 );
187 }
188 
189 int
ldap_pvt_thread_mutex_lock(ldap_pvt_thread_mutex_t * mutex)190 ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex )
191 {
192 	DWORD status;
193 	status = WaitForSingleObject( *mutex, INFINITE );
194 	return status == WAIT_FAILED ? -1 : 0;
195 }
196 
197 int
ldap_pvt_thread_mutex_unlock(ldap_pvt_thread_mutex_t * mutex)198 ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
199 {
200 	ReleaseMutex( *mutex );
201 	return ( 0 );
202 }
203 
204 int
ldap_pvt_thread_mutex_trylock(ldap_pvt_thread_mutex_t * mp)205 ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mp )
206 {
207 	DWORD status;
208 	status = WaitForSingleObject( *mp, 0 );
209 	return status == WAIT_FAILED || status == WAIT_TIMEOUT
210 		? -1 : 0;
211 }
212 
213 ldap_pvt_thread_t
ldap_pvt_thread_self(void)214 ldap_pvt_thread_self( void )
215 {
216 	return GetCurrentThreadId();
217 }
218 
219 int
ldap_pvt_thread_key_create(ldap_pvt_thread_key_t * keyp)220 ldap_pvt_thread_key_create( ldap_pvt_thread_key_t *keyp )
221 {
222 	DWORD key = TlsAlloc();
223 	if ( key != TLS_OUT_OF_INDEXES ) {
224 		*keyp = key;
225 		return 0;
226 	} else {
227 		return -1;
228 	}
229 }
230 
231 int
ldap_pvt_thread_key_destroy(ldap_pvt_thread_key_t key)232 ldap_pvt_thread_key_destroy( ldap_pvt_thread_key_t key )
233 {
234 	/* TlsFree returns 0 on failure */
235 	return( TlsFree( key ) == 0 );
236 }
237 
238 int
ldap_pvt_thread_key_setdata(ldap_pvt_thread_key_t key,void * data)239 ldap_pvt_thread_key_setdata( ldap_pvt_thread_key_t key, void *data )
240 {
241 	return ( TlsSetValue( key, data ) == 0 );
242 }
243 
244 int
ldap_pvt_thread_key_getdata(ldap_pvt_thread_key_t key,void ** data)245 ldap_pvt_thread_key_getdata( ldap_pvt_thread_key_t key, void **data )
246 {
247 	void *ptr = TlsGetValue( key );
248 	*data = ptr;
249 	return( ptr ? GetLastError() : 0 );
250 }
251 
252 #endif
253