Skip to content

Commit 3cb7263

Browse files
rongjiecomputerdscho
authored andcommitted
win32: replace pthread_cond_*() with much simpler code
The Win32 CONDITION_VARIABLE has better performance and is easier to maintain, as the code is a lot shorter now (the semantics of the CONDITION_VARIABLE matches the pthread_cond_t very well). Note: CONDITION_VARIABLE is not available in Windows XP and below, but the declared minimal Windows version required to build and run Git for Windows is Windows Vista (which is also beyond its end-of-life, but for less long than Windows XP), so that's okay. Signed-off-by: Loo Rong Jie <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]>
1 parent c35a3ea commit 3cb7263

File tree

2 files changed

+7
-159
lines changed

2 files changed

+7
-159
lines changed

compat/win32/pthread.c

Lines changed: 0 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -56,141 +56,3 @@ pthread_t pthread_self(void)
5656
t.tid = GetCurrentThreadId();
5757
return t;
5858
}
59-
60-
int pthread_cond_init(pthread_cond_t *cond, const void *unused)
61-
{
62-
cond->waiters = 0;
63-
cond->was_broadcast = 0;
64-
InitializeCriticalSection(&cond->waiters_lock);
65-
66-
cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
67-
if (!cond->sema)
68-
die("CreateSemaphore() failed");
69-
70-
cond->continue_broadcast = CreateEvent(NULL, /* security */
71-
FALSE, /* auto-reset */
72-
FALSE, /* not signaled */
73-
NULL); /* name */
74-
if (!cond->continue_broadcast)
75-
die("CreateEvent() failed");
76-
77-
return 0;
78-
}
79-
80-
int pthread_cond_destroy(pthread_cond_t *cond)
81-
{
82-
CloseHandle(cond->sema);
83-
CloseHandle(cond->continue_broadcast);
84-
DeleteCriticalSection(&cond->waiters_lock);
85-
return 0;
86-
}
87-
88-
int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex)
89-
{
90-
int last_waiter;
91-
92-
EnterCriticalSection(&cond->waiters_lock);
93-
cond->waiters++;
94-
LeaveCriticalSection(&cond->waiters_lock);
95-
96-
/*
97-
* Unlock external mutex and wait for signal.
98-
* NOTE: we've held mutex locked long enough to increment
99-
* waiters count above, so there's no problem with
100-
* leaving mutex unlocked before we wait on semaphore.
101-
*/
102-
LeaveCriticalSection(mutex);
103-
104-
/* let's wait - ignore return value */
105-
WaitForSingleObject(cond->sema, INFINITE);
106-
107-
/*
108-
* Decrease waiters count. If we are the last waiter, then we must
109-
* notify the broadcasting thread that it can continue.
110-
* But if we continued due to cond_signal, we do not have to do that
111-
* because the signaling thread knows that only one waiter continued.
112-
*/
113-
EnterCriticalSection(&cond->waiters_lock);
114-
cond->waiters--;
115-
last_waiter = cond->was_broadcast && cond->waiters == 0;
116-
LeaveCriticalSection(&cond->waiters_lock);
117-
118-
if (last_waiter) {
119-
/*
120-
* cond_broadcast was issued while mutex was held. This means
121-
* that all other waiters have continued, but are contending
122-
* for the mutex at the end of this function because the
123-
* broadcasting thread did not leave cond_broadcast, yet.
124-
* (This is so that it can be sure that each waiter has
125-
* consumed exactly one slice of the semaphor.)
126-
* The last waiter must tell the broadcasting thread that it
127-
* can go on.
128-
*/
129-
SetEvent(cond->continue_broadcast);
130-
/*
131-
* Now we go on to contend with all other waiters for
132-
* the mutex. Auf in den Kampf!
133-
*/
134-
}
135-
/* lock external mutex again */
136-
EnterCriticalSection(mutex);
137-
138-
return 0;
139-
}
140-
141-
/*
142-
* IMPORTANT: This implementation requires that pthread_cond_signal
143-
* is called while the mutex is held that is used in the corresponding
144-
* pthread_cond_wait calls!
145-
*/
146-
int pthread_cond_signal(pthread_cond_t *cond)
147-
{
148-
int have_waiters;
149-
150-
EnterCriticalSection(&cond->waiters_lock);
151-
have_waiters = cond->waiters > 0;
152-
LeaveCriticalSection(&cond->waiters_lock);
153-
154-
/*
155-
* Signal only when there are waiters
156-
*/
157-
if (have_waiters)
158-
return ReleaseSemaphore(cond->sema, 1, NULL) ?
159-
0 : err_win_to_posix(GetLastError());
160-
else
161-
return 0;
162-
}
163-
164-
/*
165-
* DOUBLY IMPORTANT: This implementation requires that pthread_cond_broadcast
166-
* is called while the mutex is held that is used in the corresponding
167-
* pthread_cond_wait calls!
168-
*/
169-
int pthread_cond_broadcast(pthread_cond_t *cond)
170-
{
171-
EnterCriticalSection(&cond->waiters_lock);
172-
173-
if ((cond->was_broadcast = cond->waiters > 0)) {
174-
/* wake up all waiters */
175-
ReleaseSemaphore(cond->sema, cond->waiters, NULL);
176-
LeaveCriticalSection(&cond->waiters_lock);
177-
/*
178-
* At this point all waiters continue. Each one takes its
179-
* slice of the semaphor. Now it's our turn to wait: Since
180-
* the external mutex is held, no thread can leave cond_wait,
181-
* yet. For this reason, we can be sure that no thread gets
182-
* a chance to eat *more* than one slice. OTOH, it means
183-
* that the last waiter must send us a wake-up.
184-
*/
185-
WaitForSingleObject(cond->continue_broadcast, INFINITE);
186-
/*
187-
* Since the external mutex is held, no thread can enter
188-
* cond_wait, and, hence, it is safe to reset this flag
189-
* without cond->waiters_lock held.
190-
*/
191-
cond->was_broadcast = 0;
192-
} else {
193-
LeaveCriticalSection(&cond->waiters_lock);
194-
}
195-
return 0;
196-
}

compat/win32/pthread.h

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,13 @@ typedef int pthread_mutexattr_t;
3232
#define pthread_mutexattr_settype(a, t) 0
3333
#define PTHREAD_MUTEX_RECURSIVE 0
3434

35-
/*
36-
* Implement simple condition variable for Windows threads, based on ACE
37-
* implementation.
38-
*
39-
* See original implementation: http://bit.ly/1vkDjo
40-
* ACE homepage: http://www.cse.wustl.edu/~schmidt/ACE.html
41-
* See also: http://www.cse.wustl.edu/~schmidt/win32-cv-1.html
42-
*/
43-
typedef struct {
44-
LONG waiters;
45-
int was_broadcast;
46-
CRITICAL_SECTION waiters_lock;
47-
HANDLE sema;
48-
HANDLE continue_broadcast;
49-
} pthread_cond_t;
50-
51-
extern int pthread_cond_init(pthread_cond_t *cond, const void *unused);
52-
extern int pthread_cond_destroy(pthread_cond_t *cond);
53-
extern int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex);
54-
extern int pthread_cond_signal(pthread_cond_t *cond);
55-
extern int pthread_cond_broadcast(pthread_cond_t *cond);
35+
#define pthread_cond_t CONDITION_VARIABLE
36+
37+
#define pthread_cond_init(a,b) InitializeConditionVariable((a))
38+
#define pthread_cond_destroy(a) do {} while (0)
39+
#define pthread_cond_wait(a,b) return_0(SleepConditionVariableCS((a), (b), INFINITE))
40+
#define pthread_cond_signal WakeConditionVariable
41+
#define pthread_cond_broadcast WakeAllConditionVariable
5642

5743
/*
5844
* Simple thread creation implementation using pthread API

0 commit comments

Comments
 (0)