]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* thread.cc: Locking and threading module functions |
2 | ||
3 | Copyright 1998, 2000 Cygnus Solutions. | |
4 | ||
5 | Written by Marco Fuykschot <marco@ddi.nl> | |
6 | ||
7 | This file is part of Cygwin. | |
8 | ||
9 | This software is a copyrighted work licensed under the terms of the | |
10 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
11 | details. */ | |
12 | ||
13 | #ifdef HAVE_CONFIG_H | |
14 | # include "config.h" | |
15 | #endif | |
16 | ||
17 | #ifdef _MT_SAFE | |
18 | #include <errno.h> | |
19 | #include "winsup.h" | |
20 | #include <assert.h> | |
21 | ||
22 | #include <stdlib.h> | |
23 | #include <syslog.h> | |
24 | ||
25 | extern int threadsafe; | |
26 | ||
27 | #define MT_INTERFACE user_data->threadinterface | |
28 | ||
29 | #define NOT_IMP(n) system_printf("not implemented %s\n",n); return 0; | |
30 | ||
31 | #define CHECKHANDLE(rval,release) \ | |
32 | if ( ! item->HandleOke() ) { \ | |
33 | if ( release ) item->used=false; \ | |
34 | return rval; }; | |
35 | ||
36 | #define GETTHREAD(n) \ | |
37 | if ( ! thread ) system_printf("thread is NULL");\ | |
38 | SetResourceLock(LOCK_THREAD_LIST,READ_LOCK,n);\ | |
39 | ThreadItem *item=user_data->threadinterface->GetThread(thread); \ | |
40 | ReleaseResourceLock(LOCK_THREAD_LIST,READ_LOCK,n); \ | |
41 | if ( ! item ) return EINVAL; \ | |
42 | CHECKHANDLE(EINVAL,0); | |
43 | ||
44 | #define GETMUTEX(n) \ | |
45 | SetResourceLock(LOCK_MUTEX_LIST,READ_LOCK,n); \ | |
46 | MutexItem* item=user_data->threadinterface->GetMutex(mutex); \ | |
47 | ReleaseResourceLock(LOCK_MUTEX_LIST,READ_LOCK,n); \ | |
48 | if ( ! item ) return EINVAL; \ | |
49 | CHECKHANDLE(EINVAL,0); | |
50 | ||
51 | #define GETSEMA(n) \ | |
52 | SetResourceLock(LOCK_SEM_LIST,READ_LOCK,n); \ | |
53 | SemaphoreItem* item=user_data->threadinterface->GetSemaphore(sem); \ | |
54 | ReleaseResourceLock(LOCK_SEM_LIST,READ_LOCK,n); \ | |
55 | if ( ! item ) return EINVAL; \ | |
56 | CHECKHANDLE(EINVAL,0); | |
57 | ||
58 | #define CHECKITEM(rn,rm,fn) \ | |
59 | if ( ! item ) { \ | |
60 | ReleaseResourceLock(rn,rm,fn); \ | |
61 | return EINVAL; }; \ | |
62 | ||
63 | struct _reent * | |
64 | _reent_clib () | |
65 | { | |
66 | int tmp = GetLastError (); | |
67 | struct __reent_t *_r = (struct __reent_t *) TlsGetValue (MT_INTERFACE->reent_index); | |
68 | ||
69 | #ifdef _CYG_THREAD_FAILSAFE | |
70 | if (_r == 0) | |
71 | { | |
72 | system_printf ("local thread storage not inited"); | |
73 | } | |
74 | #endif | |
75 | ||
76 | SetLastError (tmp); | |
77 | return _r->_clib; | |
78 | }; | |
79 | ||
80 | struct _winsup_t * | |
81 | _reent_winsup () | |
82 | { | |
83 | int tmp = GetLastError (); | |
84 | struct __reent_t *_r; | |
85 | _r = (struct __reent_t *) TlsGetValue (MT_INTERFACE->reent_index); | |
86 | #ifdef _CYG_THREAD_FAILSAFE | |
87 | if (_r == 0) | |
88 | { | |
89 | system_printf ("local thread storage not inited"); | |
90 | } | |
91 | #endif | |
92 | SetLastError (tmp); | |
93 | return _r->_winsup; | |
94 | }; | |
95 | ||
96 | void | |
97 | SetResourceLock (int _res_id, int _mode, const char *_function) | |
98 | { | |
99 | #if 0 | |
100 | if (!threadsafe) | |
101 | return; | |
102 | #endif | |
103 | thread_printf ("Set resource lock %d mode %d for %s start", _res_id, _mode, _function); | |
104 | EnterCriticalSection (user_data->resourcelocks->Lock (_res_id)); | |
105 | ||
106 | #ifdef _CYG_THREAD_FAILSAFE | |
107 | user_data->resourcelocks->owner = GetCurrentThreadId (); | |
108 | user_data->resourcelocks->count++; | |
109 | #endif | |
110 | } | |
111 | ||
112 | void | |
113 | ReleaseResourceLock (int _res_id, int _mode, const char *_function) | |
114 | { | |
115 | #if 0 | |
116 | if (!threadsafe) | |
117 | return; | |
118 | #endif | |
119 | thread_printf ("Release resource lock %d mode %d for %s done", _res_id, _mode, _function); | |
120 | ||
121 | #ifdef _CYG_THREAD_FAILSAFE | |
122 | AssertResourceOwner (_res_id, _mode); | |
123 | user_data->resourcelocks->count--; | |
124 | if (user_data->resourcelocks->count == 0) | |
125 | user_data->resourcelocks->owner = 0; | |
126 | #endif | |
127 | ||
128 | LeaveCriticalSection (user_data->resourcelocks->Lock (_res_id)); | |
129 | }; | |
130 | ||
131 | #ifdef _CYG_THREAD_FAILSAFE | |
132 | void | |
133 | AssertResourceOwner (int _res_id, int _mode) | |
134 | { | |
135 | ||
136 | thread_printf ("Assert Resource lock %d ==> for %p , real : %d , threadid %d count %d owner %d", _res_id, user_data, (myself ? myself->pid : -1), GetCurrentThreadId (), user_data->resourcelocks->count, user_data->resourcelocks->owner); | |
137 | if (user_data && (user_data->resourcelocks->owner != GetCurrentThreadId ())) | |
138 | { | |
139 | system_printf ("assertion failed, not the resource owner"); | |
140 | }; | |
141 | } | |
142 | ||
143 | #endif | |
144 | ||
145 | LPCRITICAL_SECTION | |
146 | ResourceLocks::Lock (int _resid) | |
147 | { | |
148 | if (!inited) | |
149 | { | |
150 | system_printf ("lock called before initialization"); | |
151 | }; | |
152 | ||
153 | thread_printf ("Get Resource lock %d ==> %p for %p , real : %d , threadid %d ", _resid, &lock, user_data, (myself ? myself->pid : -1), GetCurrentThreadId ()); | |
154 | return &lock; | |
155 | }; | |
156 | ||
157 | void | |
158 | ResourceLocks::Init () | |
159 | { | |
160 | thread_printf ("Init resource lock %p -> %p", this, &lock); | |
161 | ||
162 | InitializeCriticalSection (&lock); | |
163 | inited = true; | |
164 | ||
165 | #ifdef _CYG_THREAD_FAILSAFE | |
166 | owner = 0; | |
167 | count = 0; | |
168 | #endif | |
169 | ||
170 | thread_printf ("Resource lock %p inited by %p , %d", &lock, user_data, (myself ? myself->pid : -1)); | |
171 | }; | |
172 | ||
173 | void | |
174 | ResourceLocks::Delete () | |
175 | { | |
176 | if (inited) | |
177 | { | |
178 | thread_printf ("Close Resource Locks %p ", &lock); | |
179 | DeleteCriticalSection (&lock); | |
180 | inited = false; | |
181 | }; | |
182 | }; | |
183 | ||
184 | ||
185 | // Thread interface | |
186 | ||
187 | void | |
188 | MTinterface::ReleaseItem (MTitem * _item) | |
189 | { | |
190 | _item->used = false; | |
191 | }; | |
192 | ||
193 | MTitem * | |
194 | MTinterface::Find (void *_value, int (*comp) (void *, void *), register int &_index, MTList * _list) | |
195 | { | |
196 | register MTitem *current = NULL; | |
197 | for (; _index < _list->index; _index++) | |
198 | { | |
199 | current = _list->items[_index]; | |
200 | if (current->used && comp (current, _value)) | |
201 | break; | |
202 | current = NULL; | |
203 | }; | |
204 | return current; | |
205 | }; | |
206 | ||
207 | int | |
208 | MTinterface::Find (MTitem & _item, MTList * _list) | |
209 | { | |
210 | register MTitem *current; | |
211 | register int _index = 0; | |
212 | for (; _index < _list->index; _index++) | |
213 | { | |
214 | current = _list->items[_index]; | |
215 | if (current->used && current == &_item) | |
216 | break; | |
217 | }; | |
218 | return (_index == _list->index ? -1 : _index); | |
219 | }; | |
220 | ||
221 | int | |
222 | MTinterface::FindNextUnused (MTList * _list) | |
223 | { | |
224 | register int i = 0; | |
225 | for (; i < _list->index && _list->items[i] != NULL && _list->items[i]->used && _list->items[i]->joinable != 'Y'; i++); | |
226 | return i; | |
227 | }; | |
228 | ||
229 | MTitem * | |
230 | MTinterface::GetItem (int _index, MTList * _list) | |
231 | { | |
232 | return (_index < _list->index ? _list->items[_index] : NULL); | |
233 | }; | |
234 | ||
235 | MTitem * | |
236 | MTinterface::SetItem (int _index, MTitem * _item, MTList * _list) | |
237 | { | |
238 | if (_index == _list->index && _list->index < MT_MAX_ITEMS) | |
239 | _list->index++; | |
240 | return (_index < _list->index ? _list->items[_index] = _item : NULL); | |
241 | }; | |
242 | ||
243 | int | |
244 | CmpPthreadObj (void *_i, void *_value) | |
245 | { | |
246 | return ((MTitem *) _i)->Id () == *(int *) _value; | |
247 | }; | |
248 | ||
249 | int | |
250 | CmpThreadId (void *_i, void *_id) | |
251 | { | |
252 | return ((ThreadItem *) _i)->thread_id == *(DWORD *) _id; | |
253 | }; | |
254 | ||
255 | void | |
256 | MTinterface::Init0 () | |
257 | { | |
258 | for (int i = 0; i < MT_MAX_ITEMS; i++) | |
259 | { | |
260 | threadlist.items[i] = NULL; | |
261 | mutexlist.items[i] = NULL; | |
262 | semalist.items[i] = NULL; | |
263 | }; | |
264 | ||
265 | threadlist.index = 0; | |
266 | mutexlist.index = 0; | |
267 | semalist.index = 0; | |
268 | ||
269 | reent_index = TlsAlloc (); | |
270 | ||
271 | reents._clib = _impure_ptr; | |
272 | reents._winsup = &winsup_reent; | |
273 | ||
274 | winsup_reent._process_logmask = LOG_UPTO (LOG_DEBUG); | |
275 | winsup_reent._grp_pos = 0; | |
276 | winsup_reent._process_ident = 0; | |
277 | winsup_reent._process_logopt = 0; | |
278 | winsup_reent._process_facility = 0; | |
279 | ||
280 | TlsSetValue (reent_index, &reents); | |
281 | // the static reent_data will be used in the main thread | |
282 | ||
283 | }; | |
284 | ||
285 | void | |
286 | MTinterface::Init1 () | |
287 | { | |
288 | // create entry for main thread | |
289 | ||
290 | int i = FindNextUnused (&threadlist); | |
291 | assert (i == 0); | |
292 | ThreadItem *item = (ThreadItem *) GetItem (i, &threadlist); | |
293 | ||
294 | item = (ThreadItem *) SetItem (i, &mainthread, &threadlist); | |
295 | item->used = true; | |
296 | item->win32_obj_id = myself->hProcess; | |
297 | item->thread_id = GetCurrentThreadId (); | |
298 | item->function = NULL; | |
299 | ||
300 | item->sigs = NULL; | |
301 | item->sigmask = NULL; | |
302 | item->sigtodo = NULL; | |
303 | }; | |
304 | ||
305 | void | |
306 | MTinterface::ClearReent () | |
307 | { | |
308 | struct _reent *r = _REENT; | |
309 | memset (r, 0, sizeof (struct _reent)); | |
310 | ||
311 | r->_errno = 0; | |
312 | r->_stdin = &r->__sf[0]; | |
313 | r->_stdout = &r->__sf[1]; | |
314 | r->_stderr = &r->__sf[2]; | |
315 | ||
316 | }; | |
317 | ||
318 | ||
319 | ThreadItem * | |
320 | MTinterface::CreateThread (pthread_t * t, TFD (func), void *arg, pthread_attr_t a) | |
321 | { | |
322 | AssertResourceOwner (LOCK_THREAD_LIST, WRITE_LOCK | READ_LOCK); | |
323 | ||
324 | int i = FindNextUnused (&threadlist); | |
325 | ||
326 | ThreadItem *item = (ThreadItem *) GetItem (i, &threadlist); | |
327 | if (!item) | |
328 | item = (ThreadItem *) SetItem (i, new ThreadItem (), &threadlist); | |
329 | if (!item) | |
330 | system_printf ("thread creation failed"); | |
331 | ||
332 | item->used = true; | |
333 | item->function = func; | |
334 | item->arg = arg; | |
335 | item->attr = a; | |
336 | ||
337 | item->win32_obj_id = ::CreateThread (&sec_none_nih, item->attr.stacksize, | |
338 | (LPTHREAD_START_ROUTINE) thread_init_wrapper, item, 0, &item->thread_id); | |
339 | ||
340 | CHECKHANDLE (NULL, 1); | |
341 | ||
342 | *t = (pthread_t) item->win32_obj_id; | |
343 | ||
344 | return item; | |
345 | }; | |
346 | ||
347 | ||
348 | MutexItem * | |
349 | MTinterface::CreateMutex (pthread_mutex_t * mutex) | |
350 | { | |
351 | AssertResourceOwner (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK); | |
352 | ||
353 | int i = FindNextUnused (&mutexlist); | |
354 | ||
355 | MutexItem *item = (MutexItem *) GetItem (i, &mutexlist); | |
356 | if (!item) | |
357 | item = (MutexItem *) SetItem (i, new MutexItem (), &mutexlist); | |
358 | if (!item) | |
359 | system_printf ("mutex creation failed"); | |
360 | item->used = true; | |
361 | ||
362 | item->win32_obj_id = ::CreateMutex (&sec_none_nih, false, NULL); | |
363 | ||
364 | CHECKHANDLE (NULL, 1); | |
365 | ||
366 | *mutex = (pthread_mutex_t) item->win32_obj_id; | |
367 | ||
368 | return item; | |
369 | } | |
370 | ||
371 | ThreadItem * | |
372 | MTinterface::GetCallingThread () | |
373 | { | |
374 | AssertResourceOwner (LOCK_THREAD_LIST, READ_LOCK); | |
375 | DWORD id = GetCurrentThreadId (); | |
376 | int index = 0; | |
377 | return (ThreadItem *) Find (&id, &CmpThreadId, index, &threadlist); | |
378 | }; | |
379 | ||
380 | ThreadItem * | |
381 | MTinterface::GetThread (pthread_t * _t) | |
382 | { | |
383 | AssertResourceOwner (LOCK_THREAD_LIST, READ_LOCK); | |
384 | int index = 0; | |
385 | return (ThreadItem *) Find (_t, &CmpPthreadObj, index, &threadlist); | |
386 | }; | |
387 | ||
388 | MutexItem * | |
389 | MTinterface::GetMutex (pthread_mutex_t * mp) | |
390 | { | |
391 | AssertResourceOwner (LOCK_MUTEX_LIST, READ_LOCK); | |
392 | int index = 0; | |
393 | return (MutexItem *) Find (mp, &CmpPthreadObj, index, &mutexlist); | |
394 | } | |
395 | ||
396 | SemaphoreItem * | |
397 | MTinterface::GetSemaphore (sem_t * sp) | |
398 | { | |
399 | AssertResourceOwner (LOCK_SEM_LIST, READ_LOCK); | |
400 | int index = 0; | |
401 | return (SemaphoreItem *) Find (sp, &CmpPthreadObj, index, &semalist); | |
402 | } | |
403 | ||
404 | ||
405 | void | |
406 | MTitem::Destroy () | |
407 | { | |
408 | CloseHandle (win32_obj_id); | |
409 | }; | |
410 | ||
411 | int | |
412 | MutexItem::Lock () | |
413 | { | |
414 | return WaitForSingleObject (win32_obj_id, INFINITE); | |
415 | }; | |
416 | ||
417 | int | |
418 | MutexItem::TryLock () | |
419 | { | |
420 | return WaitForSingleObject (win32_obj_id, 0); | |
421 | }; | |
422 | ||
423 | int | |
424 | MutexItem::UnLock () | |
425 | { | |
426 | return ReleaseMutex (win32_obj_id); | |
427 | } | |
428 | ||
429 | SemaphoreItem * | |
430 | MTinterface::CreateSemaphore (sem_t * _s, int pshared, int _v) | |
431 | { | |
432 | AssertResourceOwner (LOCK_SEM_LIST, WRITE_LOCK | READ_LOCK); | |
433 | ||
434 | int i = FindNextUnused (&semalist); | |
435 | ||
436 | SemaphoreItem *item = (SemaphoreItem *) GetItem (i, &semalist); | |
437 | if (!item) | |
438 | item = (SemaphoreItem *) SetItem (i, new SemaphoreItem (), &semalist); | |
439 | if (!item) | |
440 | system_printf ("semaphore creation failed"); | |
441 | item->used = true; | |
442 | item->shared = pshared; | |
443 | ||
444 | item->win32_obj_id = ::CreateSemaphore (&sec_none_nih, _v, _v, NULL); | |
445 | ||
446 | CHECKHANDLE (NULL, 1); | |
447 | ||
448 | *_s = (sem_t) item->win32_obj_id; | |
449 | ||
450 | return item; | |
451 | }; | |
452 | ||
453 | int | |
454 | SemaphoreItem::Wait () | |
455 | { | |
456 | return WaitForSingleObject (win32_obj_id, INFINITE); | |
457 | }; | |
458 | ||
459 | int | |
460 | SemaphoreItem::Post () | |
461 | { | |
462 | long pc; | |
463 | return ReleaseSemaphore (win32_obj_id, 1, &pc); | |
464 | }; | |
465 | ||
466 | int | |
467 | SemaphoreItem::TryWait () | |
468 | { | |
469 | return WaitForSingleObject (win32_obj_id, 0); | |
470 | }; | |
471 | ||
472 | ||
473 | ////////////////////////// Pthreads | |
474 | ||
475 | void * | |
476 | thread_init_wrapper (void *_arg) | |
477 | { | |
478 | // Setup the local/global storage of this thread | |
479 | ||
480 | ThreadItem *thread = (ThreadItem *) _arg; | |
481 | struct __reent_t local_reent; | |
482 | struct _winsup_t local_winsup; | |
483 | struct _reent local_clib; | |
484 | ||
485 | struct sigaction _sigs[NSIG]; | |
486 | sigset_t _sig_mask; /* one set for everything to ignore. */ | |
487 | LONG _sigtodo[NSIG + __SIGOFFSET]; | |
488 | ||
489 | // setup signal structures | |
490 | thread->sigs = _sigs; | |
491 | thread->sigmask = &_sig_mask; | |
492 | thread->sigtodo = _sigtodo; | |
493 | ||
494 | memset (&local_clib, 0, sizeof (struct _reent)); | |
495 | memset (&local_winsup, 0, sizeof (struct _winsup_t)); | |
496 | ||
497 | local_clib._errno = 0; | |
498 | local_clib._stdin = &local_clib.__sf[0]; | |
499 | local_clib._stdout = &local_clib.__sf[1]; | |
500 | local_clib._stderr = &local_clib.__sf[2]; | |
501 | ||
502 | local_reent._clib = &local_clib; | |
503 | local_reent._winsup = &local_winsup; | |
504 | ||
505 | local_winsup._process_logmask = LOG_UPTO (LOG_DEBUG); | |
506 | ||
507 | ||
508 | if (!TlsSetValue (MT_INTERFACE->reent_index, &local_reent)) | |
509 | system_printf ("local storage for thread couldn't be set"); | |
510 | ||
511 | #ifdef _CYG_THREAD_FAILSAFE | |
512 | if (_REENT == _impure_ptr) | |
513 | system_printf ("local storage for thread isn't setup correctly"); | |
514 | #endif | |
515 | ||
516 | ||
517 | thread_printf ("started thread %p %p %p %p %p %p", _arg, &local_clib, _impure_ptr, thread, thread->function, thread->arg); | |
518 | ||
519 | ||
520 | // call the user's thread | |
521 | void *ret = thread->function (thread->arg); | |
522 | ||
523 | // FIX ME : cleanup code | |
524 | ||
525 | // thread->used = false; // release thread entry | |
526 | thread->return_ptr = ret; | |
527 | return ret; | |
528 | } | |
529 | ||
530 | int | |
531 | __pthread_create (pthread_t * thread, const pthread_attr_t * attr, TFD (start_routine), void *arg) | |
532 | { | |
533 | SetResourceLock (LOCK_THREAD_LIST, WRITE_LOCK | READ_LOCK, "__pthread_create"); | |
534 | ||
535 | pthread_attr_t a; | |
536 | ThreadItem *item; | |
537 | ||
538 | if (attr) | |
539 | item = MT_INTERFACE->CreateThread (thread, start_routine, arg, *attr); | |
540 | else | |
541 | { | |
542 | __pthread_attr_init (&a); | |
543 | item = MT_INTERFACE->CreateThread (thread, start_routine, arg, a); | |
544 | }; | |
545 | ||
546 | ||
547 | ||
548 | CHECKITEM (LOCK_THREAD_LIST, WRITE_LOCK | READ_LOCK, "__pthread_create") | |
549 | ||
550 | ReleaseResourceLock (LOCK_THREAD_LIST, WRITE_LOCK | READ_LOCK, "__pthread_create"); | |
551 | return 0; | |
552 | }; | |
553 | ||
554 | int | |
555 | __pthread_attr_init (pthread_attr_t * attr) | |
556 | { | |
557 | attr->stacksize = 0; | |
558 | return 0; | |
559 | }; | |
560 | ||
561 | int | |
562 | __pthread_attr_setstacksize (pthread_attr_t * attr, size_t size) | |
563 | { | |
564 | attr->stacksize = size; | |
565 | return 0; | |
566 | }; | |
567 | ||
568 | int | |
569 | __pthread_attr_getstacksize (pthread_attr_t * attr, size_t * size) | |
570 | { | |
571 | *size = attr->stacksize; | |
572 | return 0; | |
573 | }; | |
574 | ||
575 | int | |
576 | __pthread_attr_destroy (pthread_attr_t * attr) | |
577 | { | |
578 | return 0; | |
579 | }; | |
580 | ||
581 | int | |
582 | __pthread_exit (void *value_ptr) | |
583 | { | |
584 | ThreadItem *item = MT_INTERFACE->GetCallingThread(); | |
585 | item->return_ptr = value_ptr; | |
586 | ExitThread(0); | |
587 | return 0; | |
588 | } | |
589 | ||
590 | int | |
591 | __pthread_join(pthread_t * thread, void **return_val) | |
592 | { | |
593 | ThreadItem *item=user_data->threadinterface->GetThread(thread); | |
594 | ||
595 | ||
596 | if (!item) | |
597 | return ESRCH; | |
598 | ||
599 | if (item->joinable == 'N') | |
600 | { | |
601 | if (return_val) | |
602 | *return_val = NULL; | |
603 | return EINVAL; | |
604 | } | |
605 | else | |
606 | { | |
607 | item->joinable = 'N'; | |
608 | WaitForSingleObject((HANDLE)*thread, INFINITE); | |
609 | if (return_val) | |
610 | *return_val = item->return_ptr; | |
611 | }/* End if*/ | |
612 | ||
613 | return 0; | |
614 | }; | |
615 | ||
616 | int | |
617 | __pthread_detach(pthread_t * thread) | |
618 | { | |
619 | ThreadItem *item=user_data->threadinterface->GetThread(thread); | |
620 | if (!item) | |
621 | return ESRCH; | |
622 | ||
623 | if (item->joinable == 'N') | |
624 | { | |
625 | item->return_ptr = NULL; | |
626 | return EINVAL; | |
627 | } | |
628 | ||
629 | item->joinable = 'N'; | |
630 | return 0; | |
631 | } | |
632 | ||
633 | int | |
634 | __pthread_suspend(pthread_t * thread) | |
635 | { | |
636 | ThreadItem *item=user_data->threadinterface->GetThread(thread); | |
637 | if (!item) | |
638 | return ESRCH; | |
639 | ||
640 | if (item->suspended == false) | |
641 | { | |
642 | item->suspended = true; | |
643 | SuspendThread( (HANDLE)*thread); | |
644 | } | |
645 | ||
646 | return 0; | |
647 | } | |
648 | ||
649 | ||
650 | int | |
651 | __pthread_continue(pthread_t * thread) | |
652 | { | |
653 | ThreadItem *item=user_data->threadinterface->GetThread(thread); | |
654 | if (!item) | |
655 | return ESRCH; | |
656 | ||
657 | if (item->suspended == true) | |
658 | ResumeThread( (HANDLE)*thread); | |
659 | item->suspended = false; | |
660 | ||
661 | return 0; | |
662 | } | |
663 | ||
664 | ||
665 | ||
666 | ||
667 | unsigned long | |
668 | __pthread_getsequence_np (pthread_t * thread) | |
669 | { | |
670 | GETTHREAD ("__pthread_getsequence_np"); | |
671 | return item->GetThreadId (); | |
672 | }; | |
673 | ||
674 | /* Thread SpecificData */ | |
675 | int | |
676 | __pthread_key_create (pthread_key_t * key) | |
677 | { | |
678 | NOT_IMP ("_p_key_create\n"); | |
679 | }; | |
680 | ||
681 | int | |
682 | __pthread_key_delete (pthread_key_t * key) | |
683 | { | |
684 | NOT_IMP ("_p_key_delete\n"); | |
685 | }; | |
686 | int | |
687 | __pthread_setspecific (pthread_key_t * key, const void *value) | |
688 | { | |
689 | NOT_IMP ("_p_key_setsp\n"); | |
690 | }; | |
691 | void * | |
692 | __pthread_getspecific (pthread_key_t * key) | |
693 | { | |
694 | NOT_IMP ("_p_key_getsp\n"); | |
695 | }; | |
696 | ||
697 | /* Thread signal */ | |
698 | int | |
699 | __pthread_kill (pthread_t * thread, int sig) | |
700 | { | |
701 | // lock myself, for the use of thread2signal | |
702 | // two differ kills might clash: FIX ME | |
703 | GETTHREAD ("__pthread_kill"); | |
704 | ||
705 | if (item->sigs) | |
706 | myself->setthread2signal (item); | |
707 | ||
708 | int rval = sig_send (myself, sig); | |
709 | ||
710 | // unlock myself | |
711 | return rval; | |
712 | ||
713 | }; | |
714 | ||
715 | int | |
716 | __pthread_sigmask (int operation, const sigset_t * set, sigset_t * old_set) | |
717 | { | |
718 | SetResourceLock (LOCK_THREAD_LIST, READ_LOCK, "__pthread_sigmask"); | |
719 | ThreadItem *item = MT_INTERFACE->GetCallingThread (); | |
720 | ReleaseResourceLock (LOCK_THREAD_LIST, READ_LOCK, "__pthread_sigmask"); | |
721 | ||
722 | // lock this myself, for the use of thread2signal | |
723 | // two differt kills might clash: FIX ME | |
724 | ||
725 | if (item->sigs) | |
726 | myself->setthread2signal (item); | |
727 | ||
728 | int rval = sigprocmask (operation, set, old_set); | |
729 | ||
730 | // unlock this myself | |
731 | ||
732 | return rval; | |
733 | }; | |
734 | ||
735 | /* ID */ | |
736 | pthread_t | |
737 | __pthread_self () | |
738 | { | |
739 | SetResourceLock (LOCK_THREAD_LIST, READ_LOCK, "__pthread_self"); | |
740 | ||
741 | ThreadItem *item = MT_INTERFACE->GetCallingThread (); | |
742 | ||
743 | ReleaseResourceLock (LOCK_THREAD_LIST, READ_LOCK, "__pthread_self"); | |
744 | return (pthread_t) item->Id (); | |
745 | ||
746 | }; | |
747 | ||
748 | int | |
749 | __pthread_equal (pthread_t * t1, pthread_t * t2) | |
750 | { | |
751 | return (*t1 - *t2); | |
752 | }; | |
753 | ||
754 | /* Mutexes */ | |
755 | ||
756 | int | |
757 | __pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * _attr) | |
758 | { | |
759 | SetResourceLock (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK, "__pthread_mutex_init"); | |
760 | ||
761 | MutexItem *item = MT_INTERFACE->CreateMutex (mutex); | |
762 | ||
763 | CHECKITEM (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK, "__pthread_mutex_init"); | |
764 | ||
765 | ReleaseResourceLock (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK, "__pthread_mutex_init"); | |
766 | return 0; | |
767 | }; | |
768 | ||
769 | int | |
770 | __pthread_mutex_lock (pthread_mutex_t * mutex) | |
771 | { | |
772 | GETMUTEX ("_ptherad_mutex_lock"); | |
773 | ||
774 | item->Lock (); | |
775 | ||
776 | return 0; | |
777 | }; | |
778 | ||
779 | int | |
780 | __pthread_mutex_trylock (pthread_mutex_t * mutex) | |
781 | { | |
782 | GETMUTEX ("_ptherad_mutex_lock"); | |
783 | ||
784 | if (item->TryLock () == WAIT_TIMEOUT) | |
785 | return EBUSY; | |
786 | ||
787 | return 0; | |
788 | }; | |
789 | ||
790 | int | |
791 | __pthread_mutex_unlock (pthread_mutex_t * mutex) | |
792 | { | |
793 | GETMUTEX ("_ptherad_mutex_lock"); | |
794 | ||
795 | item->UnLock (); | |
796 | ||
797 | return 0; | |
798 | }; | |
799 | ||
800 | int | |
801 | __pthread_mutex_destroy (pthread_mutex_t * mutex) | |
802 | { | |
803 | SetResourceLock (LOCK_MUTEX_LIST, READ_LOCK | WRITE_LOCK, "__pthread_mutex_destroy"); | |
804 | ||
805 | MutexItem *item = MT_INTERFACE->GetMutex (mutex); | |
806 | ||
807 | CHECKITEM (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK, "__pthread_mutex_init"); | |
808 | ||
809 | item->Destroy (); | |
810 | ||
811 | MT_INTERFACE->ReleaseItem (item); | |
812 | ||
813 | ReleaseResourceLock (LOCK_MUTEX_LIST, READ_LOCK | WRITE_LOCK, "__pthread_mutex_destroy"); | |
814 | return 0; | |
815 | }; | |
816 | ||
817 | /* Semaphores */ | |
818 | int | |
819 | __sem_init (sem_t * sem, int pshared, unsigned int value) | |
820 | { | |
821 | SetResourceLock (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_init"); | |
822 | ||
823 | SemaphoreItem *item = MT_INTERFACE->CreateSemaphore (sem, pshared, value); | |
824 | ||
825 | CHECKITEM (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_init"); | |
826 | ||
827 | ReleaseResourceLock (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_init"); | |
828 | return 0; | |
829 | }; | |
830 | ||
831 | int | |
832 | __sem_destroy (sem_t * sem) | |
833 | { | |
834 | SetResourceLock (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_destroy"); | |
835 | ||
836 | SemaphoreItem *item = MT_INTERFACE->GetSemaphore (sem); | |
837 | ||
838 | CHECKITEM (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_init"); | |
839 | ||
840 | item->Destroy (); | |
841 | ||
842 | MT_INTERFACE->ReleaseItem (item); | |
843 | ||
844 | ReleaseResourceLock (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_destroy"); | |
845 | return 0; | |
846 | }; | |
847 | ||
848 | int | |
849 | __sem_wait (sem_t * sem) | |
850 | { | |
851 | GETSEMA ("__sem_wait"); | |
852 | ||
853 | item->Wait (); | |
854 | ||
855 | return 0; | |
856 | }; | |
857 | ||
858 | int | |
859 | __sem_trywait (sem_t * sem) | |
860 | { | |
861 | GETSEMA ("__sem_trywait"); | |
862 | ||
863 | if (item->TryWait () == WAIT_TIMEOUT) | |
864 | return EAGAIN; | |
865 | ||
866 | return 0; | |
867 | }; | |
868 | ||
869 | int | |
870 | __sem_post (sem_t * sem) | |
871 | { | |
872 | GETSEMA ("__sem_post"); | |
873 | ||
874 | item->Post (); | |
875 | ||
876 | return 0; | |
877 | }; | |
878 | ||
879 | ||
880 | #else | |
881 | ||
882 | // empty functions needed when makeing the dll without mt_safe support | |
883 | extern "C" | |
884 | { | |
885 | int __pthread_create (pthread_t *, const pthread_attr_t *, TFD (start_routine), void *arg) | |
886 | { | |
887 | return -1; | |
888 | }; | |
889 | int __pthread_attr_init (pthread_attr_t * attr) | |
890 | { | |
891 | return -1; | |
892 | }; | |
893 | int __pthread_attr_destroy (pthread_attr_t * attr) | |
894 | { | |
895 | return -1; | |
896 | }; | |
897 | int __pthread_attr_setstacksize (pthread_attr_t * attr, size_t size) | |
898 | { | |
899 | return -1; | |
900 | }; | |
901 | int __pthread_attr_getstacksize (pthread_attr_t * attr, size_t * size) | |
902 | { | |
903 | return -1; | |
904 | }; | |
905 | /* | |
906 | __pthread_attr_setstackaddr(...){ return -1; }; | |
907 | __pthread_attr_getstackaddr(...){ return -1; }; | |
908 | */ | |
909 | int __pthread_exit (void *value_ptr) | |
910 | { | |
911 | return -1; | |
912 | }; | |
913 | ||
914 | int __pthread_join(pthread_t thread_id, void **return_val) | |
915 | { | |
916 | return -1; | |
917 | } | |
918 | ||
919 | unsigned long __pthread_getsequence_np (pthread_t * thread) | |
920 | { | |
921 | return 0; | |
922 | }; | |
923 | int __pthread_key_create (pthread_key_t * key) | |
924 | { | |
925 | return -1; | |
926 | }; | |
927 | int __pthread_key_delete (pthread_key_t * key) | |
928 | { | |
929 | return -1; | |
930 | }; | |
931 | int __pthread_setspecific (pthread_key_t * key, const void *value) | |
932 | { | |
933 | return -1; | |
934 | }; | |
935 | void *__pthread_getspecific (pthread_key_t * key) | |
936 | { | |
937 | return NULL; | |
938 | }; | |
939 | int __pthread_kill (pthread_t * thread, int sig) | |
940 | { | |
941 | return -1; | |
942 | }; | |
943 | int __pthread_sigmask (int operation, const sigset_t * set, sigset_t * old_set) | |
944 | { | |
945 | return -1; | |
946 | }; | |
947 | pthread_t __pthread_self () | |
948 | { | |
949 | return -1; | |
950 | }; | |
951 | int __pthread_equal (pthread_t * t1, pthread_t * t2) | |
952 | { | |
953 | return -1; | |
954 | }; | |
955 | int __pthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *) | |
956 | { | |
957 | return -1; | |
958 | }; | |
959 | int __pthread_mutex_lock (pthread_mutex_t *) | |
960 | { | |
961 | return -1; | |
962 | }; | |
963 | int __pthread_mutex_trylock (pthread_mutex_t *) | |
964 | { | |
965 | return -1; | |
966 | }; | |
967 | int __pthread_mutex_unlock (pthread_mutex_t *) | |
968 | { | |
969 | return -1; | |
970 | }; | |
971 | int __pthread_mutex_destroy (pthread_mutex_t *) | |
972 | { | |
973 | return -1; | |
974 | }; | |
975 | int __sem_init (sem_t * sem, int pshared, unsigned int value) | |
976 | { | |
977 | return -1; | |
978 | }; | |
979 | int __sem_destroy (sem_t * sem) | |
980 | { | |
981 | return -1; | |
982 | }; | |
983 | int __sem_wait (sem_t * sem) | |
984 | { | |
985 | return -1; | |
986 | }; | |
987 | int __sem_trywait (sem_t * sem) | |
988 | { | |
989 | return -1; | |
990 | }; | |
991 | int __sem_post (sem_t * sem) | |
992 | { | |
993 | return -1; | |
994 | }; | |
995 | struct _reent *_reent_clib () | |
996 | { | |
997 | return NULL; | |
998 | }; | |
999 | } | |
1000 | ||
1001 | #endif // MT_SAFE |