1
/* Copyright (c) 2005 PrimeBase Technologies GmbH
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
* 2006-03-22 Paul McCullagh
23
* This file contains windows specific code
26
#include "xt_config.h"
29
#include <my_pthread.h>
34
#include <sys/resource.h>
40
#include "pthread_xt.h"
41
#include "thread_xt.h"
45
xtPublic void xt_p_init_threading(void)
49
xtPublic int xt_p_set_normal_priority(pthread_t thr)
51
if (!SetThreadPriority (thr, THREAD_PRIORITY_NORMAL))
52
return GetLastError();
56
xtPublic int xt_p_set_low_priority(pthread_t thr)
58
if (!SetThreadPriority (thr, THREAD_PRIORITY_LOWEST))
59
return GetLastError();
63
xtPublic int xt_p_set_high_priority(pthread_t thr)
65
if (!SetThreadPriority (thr, THREAD_PRIORITY_HIGHEST))
66
return GetLastError();
70
#define XT_RWLOCK_MAGIC 0x78AC390E
72
#ifdef XT_THREAD_LOCK_INFO
73
xtPublic int xt_p_mutex_init(xt_mutex_type *mutex, const pthread_mutexattr_t *attr, const char *n)
75
xtPublic int xt_p_mutex_init(xt_mutex_type *mutex, const pthread_mutexattr_t *attr)
78
InitializeCriticalSection(&mutex->mt_cs);
79
#ifdef XT_THREAD_LOCK_INFO
80
xt_thread_lock_info_init(&mutex->mt_lock_info, mutex);
86
xtPublic int xt_p_mutex_destroy(xt_mutex_type *mutex)
88
DeleteCriticalSection(&mutex->mt_cs);
89
#ifdef XT_THREAD_LOCK_INFO
90
xt_thread_lock_info_free(&mutex->mt_lock_info);
95
xtPublic int xt_p_mutex_lock(xt_mutex_type *mx)
97
EnterCriticalSection(&mx->mt_cs);
98
#ifdef XT_THREAD_LOCK_INFO
99
xt_thread_lock_info_add_owner(&mx->mt_lock_info);
104
xtPublic int xt_p_mutex_unlock(xt_mutex_type *mx)
106
LeaveCriticalSection(&mx->mt_cs);
107
#ifdef XT_THREAD_LOCK_INFO
108
xt_thread_lock_info_release_owner(&mx->mt_lock_info);
113
xtPublic int xt_p_mutex_trylock(xt_mutex_type *mutex)
115
#if(_WIN32_WINNT >= 0x0400)
116
/* NOTE: MySQL bug! was using?!
117
* pthread_mutex_trylock(A) (WaitForSingleObject((A), 0) == WAIT_TIMEOUT)
119
if (TryEnterCriticalSection(&mutex->mt_cs)) {
120
#ifdef XT_THREAD_LOCK_INFO
121
xt_thread_lock_info_add_owner(&mutex->mt_lock_info);
127
EnterCriticalSection(&mutex->mt_cs);
128
#ifdef XT_THREAD_LOCK_INFO
129
xt_thread_lock_info_add_owner(&mutex->mt_lock_info);
135
#ifdef XT_THREAD_LOCK_INFO
136
xtPublic int xt_p_rwlock_init(xt_rwlock_type *rwl, const pthread_condattr_t *attr, const char *n)
138
xtPublic int xt_p_rwlock_init(xt_rwlock_type *rwl, const pthread_condattr_t *attr)
144
return ERROR_BAD_ARGUMENTS;
146
rwl->rw_sh_count = 0;
147
rwl->rw_ex_count = 0;
148
rwl->rw_sh_complete_count = 0;
150
result = xt_p_mutex_init_with_autoname(&rwl->rw_ex_lock, NULL);
154
result = xt_p_mutex_init_with_autoname(&rwl->rw_sh_lock, NULL);
158
result = pthread_cond_init(&rwl->rw_sh_cond, NULL);
162
rwl->rw_magic = XT_RWLOCK_MAGIC;
163
#ifdef XT_THREAD_LOCK_INFO
165
xt_thread_lock_info_init(&rwl->rw_lock_info, rwl);
170
(void) xt_p_mutex_destroy(&rwl->rw_sh_lock);
173
(void) xt_p_mutex_destroy(&rwl->rw_ex_lock);
179
xtPublic int xt_p_rwlock_destroy(xt_rwlock_type *rwl)
181
int result = 0, result1 = 0, result2 = 0;
184
return ERROR_BAD_ARGUMENTS;
186
if (rwl->rw_magic != XT_RWLOCK_MAGIC)
187
return ERROR_BAD_ARGUMENTS;
189
if ((result = xt_p_mutex_lock(&rwl->rw_ex_lock)) != 0)
192
if ((result = xt_p_mutex_lock(&rwl->rw_sh_lock)) != 0) {
193
(void) xt_p_mutex_unlock(&rwl->rw_ex_lock);
198
* Check whether any threads own/wait for the lock (wait for ex.access);
199
* report "BUSY" if so.
201
if (rwl->rw_ex_count > 0 || rwl->rw_sh_count > rwl->rw_sh_complete_count) {
202
result = xt_p_mutex_unlock(&rwl->rw_sh_lock);
203
result1 = xt_p_mutex_unlock(&rwl->rw_ex_lock);
204
result2 = ERROR_BUSY;
209
if ((result = xt_p_mutex_unlock(&rwl->rw_sh_lock)) != 0)
211
xt_p_mutex_unlock(&rwl->rw_ex_lock);
215
if ((result = xt_p_mutex_unlock(&rwl->rw_ex_lock)) != 0)
218
result = pthread_cond_destroy(&rwl->rw_sh_cond);
219
result1 = xt_p_mutex_destroy(&rwl->rw_sh_lock);
220
result2 = xt_p_mutex_destroy(&rwl->rw_ex_lock);
223
#ifdef XT_THREAD_LOCK_INFO
224
xt_thread_lock_info_free(&rwl->rw_lock_info);
227
return (result != 0) ? result : ((result1 != 0) ? result1 : result2);
231
xtPublic int xt_p_rwlock_rdlock(xt_rwlock_type *rwl)
236
return ERROR_BAD_ARGUMENTS;
238
if (rwl->rw_magic != XT_RWLOCK_MAGIC)
239
return ERROR_BAD_ARGUMENTS;
241
if ((result = xt_p_mutex_lock(&rwl->rw_ex_lock)) != 0)
244
if (++rwl->rw_sh_count == INT_MAX) {
245
if ((result = xt_p_mutex_lock(&rwl->rw_sh_lock)) != 0)
247
(void) xt_p_mutex_unlock(&rwl->rw_ex_lock);
251
rwl->rw_sh_count -= rwl->rw_sh_complete_count;
252
rwl->rw_sh_complete_count = 0;
254
if ((result = xt_p_mutex_unlock(&rwl->rw_sh_lock)) != 0)
256
(void) xt_p_mutex_unlock(&rwl->rw_ex_lock);
261
#ifdef XT_THREAD_LOCK_INFO
262
xt_thread_lock_info_add_owner(&rwl->rw_lock_info);
265
return (xt_p_mutex_unlock (&(rwl->rw_ex_lock)));
268
xtPublic int xt_p_rwlock_wrlock(xt_rwlock_type *rwl)
273
return ERROR_BAD_ARGUMENTS;
275
if (rwl->rw_magic != XT_RWLOCK_MAGIC)
276
return ERROR_BAD_ARGUMENTS;
278
if ((result = xt_p_mutex_lock (&rwl->rw_ex_lock)) != 0)
281
if ((result = xt_p_mutex_lock (&rwl->rw_sh_lock)) != 0) {
282
(void) xt_p_mutex_unlock (&rwl->rw_ex_lock);
286
if (rwl->rw_ex_count == 0) {
287
if (rwl->rw_sh_complete_count > 0) {
288
rwl->rw_sh_count -= rwl->rw_sh_complete_count;
289
rwl->rw_sh_complete_count = 0;
292
if (rwl->rw_sh_count > 0) {
293
rwl->rw_sh_complete_count = -rwl->rw_sh_count;
296
result = pthread_cond_wait (&rwl->rw_sh_cond, &rwl->rw_sh_lock.mt_cs);
298
while (result == 0 && rwl->rw_sh_complete_count < 0);
301
rwl->rw_sh_count = 0;
308
#ifdef XT_THREAD_LOCK_INFO
309
xt_thread_lock_info_add_owner(&rwl->rw_lock_info);
315
xtPublic xtBool xt_p_rwlock_try_wrlock(xt_rwlock_type *rwl)
322
if (rwl->rw_magic != XT_RWLOCK_MAGIC)
325
if ((result = xt_p_mutex_trylock(&rwl->rw_ex_lock)) != 0)
328
if ((result = xt_p_mutex_lock(&rwl->rw_sh_lock)) != 0) {
329
(void) xt_p_mutex_unlock(&rwl->rw_ex_lock);
333
if (rwl->rw_ex_count == 0) {
334
if (rwl->rw_sh_complete_count > 0) {
335
rwl->rw_sh_count -= rwl->rw_sh_complete_count;
336
rwl->rw_sh_complete_count = 0;
339
if (rwl->rw_sh_count > 0) {
340
rwl->rw_sh_complete_count = -rwl->rw_sh_count;
343
result = pthread_cond_wait (&rwl->rw_sh_cond, &rwl->rw_sh_lock.mt_cs);
345
while (result == 0 && rwl->rw_sh_complete_count < 0);
348
rwl->rw_sh_count = 0;
355
#ifdef XT_THREAD_LOCK_INFO
356
xt_thread_lock_info_add_owner(&rwl->rw_lock_info);
362
xtPublic int xt_p_rwlock_unlock(xt_rwlock_type *rwl)
367
return (ERROR_BAD_ARGUMENTS);
369
if (rwl->rw_magic != XT_RWLOCK_MAGIC)
370
return ERROR_BAD_ARGUMENTS;
372
if (rwl->rw_ex_count == 0) {
373
if ((result = xt_p_mutex_lock(&rwl->rw_sh_lock)) != 0)
376
if (++rwl->rw_sh_complete_count == 0)
377
result = pthread_cond_signal(&rwl->rw_sh_cond);
379
result1 = xt_p_mutex_unlock(&rwl->rw_sh_lock);
384
result = xt_p_mutex_unlock(&rwl->rw_sh_lock);
385
result1 = xt_p_mutex_unlock(&rwl->rw_ex_lock);
388
#ifdef XT_THREAD_LOCK_INFO
389
xt_thread_lock_info_release_owner(&rwl->rw_lock_info);
392
return ((result != 0) ? result : result1);
395
xtPublic int xt_p_cond_wait(xt_cond_type *cond, xt_mutex_type *mutex)
397
return xt_p_cond_timedwait(cond, mutex, NULL);
400
xtPublic int xt_p_cond_timedwait(xt_cond_type *cond, xt_mutex_type *mt, struct timespec *abstime)
402
pthread_mutex_t *mutex = &mt->mt_cs;
407
if (abstime != NULL) {
408
GetSystemTimeAsFileTime(&now.ft);
410
timeout = (long)((abstime->tv.i64 - now.i64) / 10000);
413
if (timeout > abstime->max_timeout_msec)
414
timeout = abstime->max_timeout_msec;
419
WaitForSingleObject(cond->broadcast_block_event, INFINITE);
421
EnterCriticalSection(&cond->lock_waiting);
423
LeaveCriticalSection(&cond->lock_waiting);
425
LeaveCriticalSection(mutex);
427
result= WaitForMultipleObjects(2, cond->events, FALSE, timeout);
429
EnterCriticalSection(&cond->lock_waiting);
432
if (cond->waiting == 0) {
433
/* The last waiter must reset the broadcast
434
* state (whther there was a broadcast or not)!
436
ResetEvent(cond->events[xt_cond_type::BROADCAST]);
437
SetEvent(cond->broadcast_block_event);
439
LeaveCriticalSection(&cond->lock_waiting);
441
EnterCriticalSection(mutex);
443
return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
446
xtPublic int xt_p_join(pthread_t thread, void **value)
451
switch (WaitForSingleObject(thread, 10000)) {
455
/* Don't do this! According to the Win docs:
456
* _endthread automatically closes the thread handle
457
* (whereas _endthreadex does not). Therefore, when using
458
* _beginthread and _endthread, do not explicitly close the
459
* thread handle by calling the Win32 CloseHandle API.
462
/* This is done so that if the thread was not [yet] in the running
463
* state when this function was called we won't deadlock here.
465
if (GetExitCodeThread(thread, &exitcode) && (exitcode == STILL_ACTIVE))
469
return GetLastError();
479
#define POLICY SCHED_RR
481
#define POLICY pth_policy
484
static int pth_policy;
485
static int pth_normal_priority;
486
static int pth_min_priority;
487
static int pth_max_priority;
489
/* Return zero if the priority was set OK,
492
static int pth_set_priority(pthread_t thread, int priority)
494
struct sched_param sp;
496
memset(&sp, 0, sizeof(struct sched_param));
497
sp.sched_priority = priority;
498
return pthread_setschedparam(thread, POLICY, &sp);
501
static void pth_get_priority_limits(void)
503
XTThreadPtr self = NULL;
504
struct sched_param sp;
508
/* Save original priority: */
509
err = pthread_getschedparam(pthread_self(), &pth_policy, &sp);
511
xt_throw_errno(XT_CONTEXT, err);
514
pth_normal_priority = sp.sched_priority;
516
start = sp.sched_priority;
519
pth_min_priority = sched_get_priority_min(sched_getscheduler(0));
520
pth_max_priority = sched_get_priority_max(sched_getscheduler(0));
522
/* Search for the minimum priority: */
523
pth_min_priority = start;
525
/* 2007-03-01: Corrected, pth_set_priority returns the error code
526
* (thanks to Hakan for pointing out this bug!)
528
if (pth_set_priority(pthread_self(), pth_min_priority-1) != 0)
533
/* Search for the maximum priority: */
534
pth_max_priority = start;
536
if (pth_set_priority(pthread_self(), pth_max_priority+1) != 0)
541
/* Restore original priority: */
542
pthread_setschedparam(pthread_self(), pth_policy, &sp);
546
xtPublic void xt_p_init_threading(void)
548
pth_get_priority_limits();
551
xtPublic int xt_p_set_low_priority(pthread_t thr)
553
if (pth_min_priority == pth_max_priority) {
554
/* Under Linux the priority of normal (non-runtime)
555
* threads are set using the standard methods
556
* for setting process priority.
559
/* We could set who == 0 because it should have the same affect
563
/* -20 = highest, 20 = lowest */
564
if (setpriority(PRIO_PROCESS, getpid(), 20) == -1)
568
return pth_set_priority(thr, pth_min_priority);
571
xtPublic int xt_p_set_normal_priority(pthread_t thr)
573
if (pth_min_priority == pth_max_priority) {
574
if (setpriority(PRIO_PROCESS, getpid(), 0) == -1)
578
return pth_set_priority(thr, pth_normal_priority);
581
xtPublic int xt_p_set_high_priority(pthread_t thr)
583
if (pth_min_priority == pth_max_priority) {
584
if (setpriority(PRIO_PROCESS, getpid(), -20) == -1) {
585
if (errno == EACCES) {
586
if (setpriority(PRIO_PROCESS, getpid(), 0) == -1) {
594
return pth_set_priority(thr, pth_max_priority);
599
xtPublic int xt_p_mutex_lock(xt_mutex_type *mutex, u_int line, const char *file)
601
XTThreadPtr self = xt_get_self();
604
ASSERT_NS(mutex->mu_init == 12345);
605
r = pthread_mutex_lock(&mutex->mu_plock);
608
printf("==LOCK mutex %d %s:%d\n", (int) mutex->mu_trace, file, (int) line);
609
ASSERT_NS(!mutex->mu_locker);
610
mutex->mu_locker = self;
611
mutex->mu_line = line;
612
mutex->mu_file = file;
614
#ifdef XT_THREAD_LOCK_INFO
615
xt_thread_lock_info_add_owner(&mutex->mu_lock_info);
620
xtPublic int xt_p_mutex_unlock(xt_mutex_type *mutex)
622
XTThreadPtr self = xt_get_self();
624
ASSERT_NS(mutex->mu_init == 12345);
625
ASSERT_NS(mutex->mu_locker == self);
626
mutex->mu_locker = NULL;
628
printf("UNLOCK mutex %d\n", (int) mutex->mu_trace);
629
#ifdef XT_THREAD_LOCK_INFO
630
xt_thread_lock_info_release_owner(&mutex->mu_lock_info);
632
return pthread_mutex_unlock(&mutex->mu_plock);
635
xtPublic int xt_p_mutex_destroy(xt_mutex_type *mutex)
637
ASSERT_NS(mutex->mu_init == 12345 || !mutex->mu_init || mutex->mu_init == 11111);
638
mutex->mu_init = 11111;
639
#ifdef XT_THREAD_LOCK_INFO
640
xt_thread_lock_info_free(&mutex->mu_lock_info);
642
return pthread_mutex_destroy(&mutex->mu_plock);
645
xtPublic int xt_p_mutex_trylock(xt_mutex_type *mutex)
647
XTThreadPtr self = xt_get_self();
650
ASSERT_NS(mutex->mu_init == 12345);
651
r = pthread_mutex_trylock(&mutex->mu_plock);
653
ASSERT_NS(!mutex->mu_locker);
654
mutex->mu_locker = self;
655
#ifdef XT_THREAD_LOCK_INFO
656
xt_thread_lock_info_add_owner(&mutex->mu_lock_info);
662
#ifdef XT_THREAD_LOCK_INFO
663
xtPublic int xt_p_mutex_init(xt_mutex_type *mutex, const pthread_mutexattr_t *attr, const char *n)
665
xtPublic int xt_p_mutex_init(xt_mutex_type *mutex, const pthread_mutexattr_t *attr)
668
mutex->mu_init = 12345;
669
mutex->mu_trace = FALSE;
670
mutex->mu_locker = NULL;
671
#ifdef XT_THREAD_LOCK_INFO
673
xt_thread_lock_info_init(&mutex->mu_lock_info, mutex);
675
return pthread_mutex_init(&mutex->mu_plock, attr);
678
xtPublic int xt_p_cond_wait(xt_cond_type *cond, xt_mutex_type *mutex)
680
XTThreadPtr self = xt_get_self();
683
ASSERT_NS(mutex->mu_init == 12345);
684
ASSERT_NS(mutex->mu_locker == self);
685
mutex->mu_locker = NULL;
686
r = pthread_cond_wait(cond, &mutex->mu_plock);
687
ASSERT_NS(!mutex->mu_locker);
688
mutex->mu_locker = self;
692
xtPublic int xt_p_cond_timedwait(xt_cond_type *cond, xt_mutex_type *mutex, const struct timespec *abstime)
694
XTThreadPtr self = xt_get_self();
697
ASSERT_NS(mutex->mu_init == 12345);
698
ASSERT_NS(mutex->mu_locker == self);
699
mutex->mu_locker = NULL;
700
r = pthread_cond_timedwait(cond, &mutex->mu_plock, abstime);
701
ASSERT_NS(!mutex->mu_locker);
702
mutex->mu_locker = self;
706
xtPublic int xt_p_rwlock_rdlock(xt_rwlock_type *rwlock)
710
ASSERT_NS(rwlock->rw_init == 67890);
711
r = pthread_rwlock_rdlock(&rwlock->rw_plock);
712
#ifdef XT_THREAD_LOCK_INFO
713
xt_thread_lock_info_add_owner(&rwlock->rw_lock_info);
718
xtPublic int xt_p_rwlock_wrlock(xt_rwlock_type *rwlock)
720
XTThreadPtr self = xt_get_self();
723
ASSERT_NS(rwlock->rw_init == 67890);
724
r = pthread_rwlock_wrlock(&rwlock->rw_plock);
726
ASSERT_NS(!rwlock->rw_locker);
727
rwlock->rw_locker = self;
729
#ifdef XT_THREAD_LOCK_INFO
730
xt_thread_lock_info_add_owner(&rwlock->rw_lock_info);
735
xtPublic xtBool xt_p_rwlock_try_wrlock(xt_rwlock_type *rwlock)
737
XTThreadPtr self = xt_get_self();
740
ASSERT_NS(rwlock->rw_init == 67890);
741
r = pthread_rwlock_trywrlock(&rwlock->rw_plock);
743
ASSERT_NS(!rwlock->rw_locker);
744
rwlock->rw_locker = self;
745
#ifdef XT_THREAD_LOCK_INFO
746
xt_thread_lock_info_add_owner(&rwlock->rw_lock_info);
752
xtPublic int xt_p_rwlock_unlock(xt_rwlock_type *rwlock)
754
XTThreadPtr self = xt_get_self();
756
ASSERT_NS(rwlock->rw_init == 67890);
757
if (rwlock->rw_locker) {
758
ASSERT_NS(rwlock->rw_locker == self);
759
rwlock->rw_locker = NULL;
761
#ifdef XT_THREAD_LOCK_INFO
762
xt_thread_lock_info_release_owner(&rwlock->rw_lock_info);
764
return pthread_rwlock_unlock(&rwlock->rw_plock);
767
xtPublic int xt_p_rwlock_destroy(xt_rwlock_type *rwlock)
769
ASSERT_NS(rwlock->rw_init == 67890);
771
#ifdef XT_THREAD_LOCK_INFO
772
xt_thread_lock_info_free(&rwlock->rw_lock_info);
774
return pthread_rwlock_destroy(&rwlock->rw_plock);
777
#ifdef XT_THREAD_LOCK_INFO
778
xtPublic int xt_p_rwlock_init(xt_rwlock_type *rwlock, const pthread_rwlockattr_t *attr, const char *n)
780
xtPublic int xt_p_rwlock_init(xt_rwlock_type *rwlock, const pthread_rwlockattr_t *attr)
783
rwlock->rw_init = 67890;
784
rwlock->rw_readers = 0;
785
rwlock->rw_locker = NULL;
786
#ifdef XT_THREAD_LOCK_INFO
788
xt_thread_lock_info_init(&rwlock->rw_lock_info, rwlock);
790
return pthread_rwlock_init(&rwlock->rw_plock, attr);
793
#endif // DEBUG_LOCKING