2 * Win32 critical sections
4 * Copyright 1998 Alexandre Julliard
7 /* Note: critical sections are not implemented exactly the same way
8 * than under NT (LockSemaphore should be a real semaphore handle).
9 * But since they are even more different under Win95, it probably
16 #include <sys/types.h>
28 THREAD_QUEUE wait_queue
;
32 /* On some systems this is supposed to be defined in the program */
33 #ifndef HAVE_UNION_SEMUN
41 static BOOL32
CRIT_SECTION_Signaled( K32OBJ
*obj
, DWORD thread_id
);
42 static BOOL32
CRIT_SECTION_Satisfied( K32OBJ
*obj
, DWORD thread_id
);
43 static void CRIT_SECTION_AddWait( K32OBJ
*obj
, DWORD thread_id
);
44 static void CRIT_SECTION_RemoveWait( K32OBJ
*obj
, DWORD thread_id
);
45 static void CRIT_SECTION_Destroy( K32OBJ
*obj
);
47 const K32OBJ_OPS CRITICAL_SECTION_Ops
=
49 CRIT_SECTION_Signaled
, /* signaled */
50 CRIT_SECTION_Satisfied
, /* satisfied */
51 CRIT_SECTION_AddWait
, /* add_wait */
52 CRIT_SECTION_RemoveWait
, /* remove_wait */
53 CRIT_SECTION_Destroy
/* destroy */
56 /***********************************************************************
57 * InitializeCriticalSection (KERNEL32.472) (NTDLL.406)
59 void WINAPI
InitializeCriticalSection( CRITICAL_SECTION
*crit
)
64 crit
->RecursionCount
= 0;
65 crit
->OwningThread
= 0;
66 crit
->LockSemaphore
= 0;
69 if (!(obj
= (CRIT_SECTION
*)HeapAlloc( SystemHeap
, 0, sizeof(*obj
) )))
70 return; /* No way to return an error... */
71 obj
->header
.type
= K32OBJ_CRITICAL_SECTION
;
72 obj
->header
.refcount
= 1;
73 obj
->wait_queue
= NULL
;
74 obj
->signaled
= FALSE
;
75 crit
->LockSemaphore
= (HANDLE32
)obj
;
76 crit
->Reserved
= (DWORD
)-1;
81 crit
->Reserved
= (DWORD
)semget( IPC_PRIVATE
, 1, IPC_CREAT
| 0777 );
82 if (crit
->Reserved
== (DWORD
)-1)
88 semctl( (int)crit
->Reserved
, 0, SETVAL
, val
);
93 /***********************************************************************
94 * DeleteCriticalSection (KERNEL32.185) (NTDLL.327)
96 void WINAPI
DeleteCriticalSection( CRITICAL_SECTION
*crit
)
98 CRIT_SECTION
*obj
= (CRIT_SECTION
*)crit
->LockSemaphore
;
102 if (crit
->RecursionCount
) /* Should not happen */
103 fprintf( stderr
, "Deleting owned critical section (%p)\n", crit
);
104 crit
->LockCount
= -1;
105 crit
->RecursionCount
= 0;
106 crit
->OwningThread
= 0;
107 crit
->LockSemaphore
= 0;
108 K32OBJ_DecCount( &obj
->header
);
110 else if (crit
->Reserved
!= (DWORD
)-1)
112 semctl( (int)crit
->Reserved
, 0, IPC_RMID
, (union semun
)0 );
117 /***********************************************************************
118 * EnterCriticalSection (KERNEL32.195) (NTDLL.344)
120 void WINAPI
EnterCriticalSection( CRITICAL_SECTION
*crit
)
122 if (InterlockedIncrement( &crit
->LockCount
))
124 if (crit
->OwningThread
== GetCurrentThreadId())
126 crit
->RecursionCount
++;
129 /* Now wait for it */
130 if (crit
->LockSemaphore
)
132 WAIT_STRUCT
*wait
= &THREAD_Current()->wait_struct
;
135 wait
->signaled
= WAIT_FAILED
;
136 wait
->wait_all
= FALSE
;
137 wait
->objs
[0] = (K32OBJ
*)crit
->LockSemaphore
;
138 K32OBJ_IncCount( wait
->objs
[0] );
139 SYNC_WaitForCondition( wait
, INFINITE32
);
140 K32OBJ_DecCount( wait
->objs
[0] );
143 else if (crit
->Reserved
!= (DWORD
)-1)
149 sop
.sem_flg
= SEM_UNDO
;
152 ret
= semop( (int)crit
->Reserved
, &sop
, 1 );
153 } while ((ret
== -1) && (errno
== EINTR
));
157 fprintf( stderr
, "Uninitialized critical section (%p)\n", crit
);
161 crit
->OwningThread
= GetCurrentThreadId();
162 crit
->RecursionCount
= 1;
166 /***********************************************************************
167 * TryEnterCriticalSection (KERNEL32.898) (NTDLL.969)
169 BOOL32 WINAPI
TryEnterCriticalSection( CRITICAL_SECTION
*crit
)
171 if (InterlockedIncrement( &crit
->LockCount
))
173 if (crit
->OwningThread
== GetCurrentThreadId())
175 crit
->RecursionCount
++;
178 /* FIXME: this doesn't work */
179 InterlockedDecrement( &crit
->LockCount
);
182 crit
->OwningThread
= GetCurrentThreadId();
183 crit
->RecursionCount
= 1;
188 /***********************************************************************
189 * LeaveCriticalSection (KERNEL32.494) (NTDLL.426)
191 void WINAPI
LeaveCriticalSection( CRITICAL_SECTION
*crit
)
193 if (crit
->OwningThread
!= GetCurrentThreadId()) return;
195 if (--crit
->RecursionCount
)
197 InterlockedDecrement( &crit
->LockCount
);
200 crit
->OwningThread
= 0;
201 if (InterlockedDecrement( &crit
->LockCount
) >= 0)
203 /* Someone is waiting */
204 if (crit
->LockSemaphore
)
206 CRIT_SECTION
*obj
= (CRIT_SECTION
*)crit
->LockSemaphore
;
208 obj
->signaled
= TRUE
;
209 SYNC_WakeUp( &obj
->wait_queue
, 1 );
212 else if (crit
->Reserved
!= (DWORD
)-1)
217 sop
.sem_flg
= SEM_UNDO
;
218 semop( (int)crit
->Reserved
, &sop
, 1 );
224 /***********************************************************************
225 * MakeCriticalSectionGlobal (KERNEL32.515)
227 void WINAPI
MakeCriticalSectionGlobal( CRITICAL_SECTION
*crit
)
229 /* Nothing to do: a critical section is always global */
233 /***********************************************************************
234 * ReinitializeCriticalSection (KERNEL32.581)
236 void WINAPI
ReinitializeCriticalSection( CRITICAL_SECTION
*crit
)
238 DeleteCriticalSection( crit
);
239 InitializeCriticalSection( crit
);
243 /***********************************************************************
244 * CRIT_SECTION_Signaled
246 static BOOL32
CRIT_SECTION_Signaled( K32OBJ
*obj
, DWORD thread_id
)
248 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
249 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
250 return crit
->signaled
;
254 /***********************************************************************
255 * CRIT_SECTION_Satisfied
257 * Wait on this object has been satisfied.
259 static BOOL32
CRIT_SECTION_Satisfied( K32OBJ
*obj
, DWORD thread_id
)
261 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
262 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
263 /* Only one thread is allowed to wake up */
264 crit
->signaled
= FALSE
;
265 return FALSE
; /* Not abandoned */
269 /***********************************************************************
270 * CRIT_SECTION_AddWait
272 * Add thread to object wait queue.
274 static void CRIT_SECTION_AddWait( K32OBJ
*obj
, DWORD thread_id
)
276 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
277 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
278 THREAD_AddQueue( &crit
->wait_queue
, THREAD_ID_TO_THDB(thread_id
) );
282 /***********************************************************************
283 * CRIT_SECTION_RemoveWait
285 * Remove current thread from object wait queue.
287 static void CRIT_SECTION_RemoveWait( K32OBJ
*obj
, DWORD thread_id
)
289 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
290 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
291 THREAD_RemoveQueue( &crit
->wait_queue
, THREAD_ID_TO_THDB(thread_id
) );
295 /***********************************************************************
296 * CRIT_SECTION_Destroy
298 static void CRIT_SECTION_Destroy( K32OBJ
*obj
)
300 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
301 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
302 /* There cannot be any thread on the list since the ref count is 0 */
303 assert( crit
->wait_queue
== NULL
);
304 obj
->type
= K32OBJ_UNKNOWN
;
305 HeapFree( SystemHeap
, 0, crit
);