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>
30 THREAD_QUEUE wait_queue
;
34 /* On some systems this is supposed to be defined in the program */
35 #ifndef HAVE_UNION_SEMUN
43 static BOOL32
CRIT_SECTION_Signaled( K32OBJ
*obj
, DWORD thread_id
);
44 static BOOL32
CRIT_SECTION_Satisfied( K32OBJ
*obj
, DWORD thread_id
);
45 static void CRIT_SECTION_AddWait( K32OBJ
*obj
, DWORD thread_id
);
46 static void CRIT_SECTION_RemoveWait( K32OBJ
*obj
, DWORD thread_id
);
47 static void CRIT_SECTION_Destroy( K32OBJ
*obj
);
49 const K32OBJ_OPS CRITICAL_SECTION_Ops
=
51 CRIT_SECTION_Signaled
, /* signaled */
52 CRIT_SECTION_Satisfied
, /* satisfied */
53 CRIT_SECTION_AddWait
, /* add_wait */
54 CRIT_SECTION_RemoveWait
, /* remove_wait */
57 CRIT_SECTION_Destroy
/* destroy */
60 /***********************************************************************
61 * InitializeCriticalSection (KERNEL32.472) (NTDLL.406)
63 void WINAPI
InitializeCriticalSection( CRITICAL_SECTION
*crit
)
68 crit
->RecursionCount
= 0;
69 crit
->OwningThread
= 0;
70 crit
->LockSemaphore
= 0;
73 if (!(obj
= (CRIT_SECTION
*)HeapAlloc( SystemHeap
, 0, sizeof(*obj
) )))
74 return; /* No way to return an error... */
75 obj
->header
.type
= K32OBJ_CRITICAL_SECTION
;
76 obj
->header
.refcount
= 1;
77 obj
->wait_queue
= NULL
;
78 obj
->signaled
= FALSE
;
79 crit
->LockSemaphore
= (HANDLE32
)obj
;
80 crit
->Reserved
= (DWORD
)-1;
85 crit
->Reserved
= (DWORD
)semget( IPC_PRIVATE
, 1, IPC_CREAT
| 0777 );
86 if (crit
->Reserved
== (DWORD
)-1)
92 semctl( (int)crit
->Reserved
, 0, SETVAL
, val
);
97 /***********************************************************************
98 * DeleteCriticalSection (KERNEL32.185) (NTDLL.327)
100 void WINAPI
DeleteCriticalSection( CRITICAL_SECTION
*crit
)
102 CRIT_SECTION
*obj
= (CRIT_SECTION
*)crit
->LockSemaphore
;
106 if (crit
->RecursionCount
) /* Should not happen */
107 MSG("Deleting owned critical section (%p)\n", crit
);
108 crit
->LockCount
= -1;
109 crit
->RecursionCount
= 0;
110 crit
->OwningThread
= 0;
111 crit
->LockSemaphore
= 0;
112 K32OBJ_DecCount( &obj
->header
);
114 else if (crit
->Reserved
!= (DWORD
)-1)
116 semctl( (int)crit
->Reserved
, 0, IPC_RMID
, (union semun
)0 );
121 /***********************************************************************
122 * EnterCriticalSection (KERNEL32.195) (NTDLL.344)
124 void WINAPI
EnterCriticalSection( CRITICAL_SECTION
*crit
)
126 if ( (crit
->Reserved
==-1) && !(crit
->LockSemaphore
) &&
127 (crit
!=HEAP_SystemLock
)
129 FIXME(win32
,"entering uninitialized section(%p)?\n",crit
);
130 InitializeCriticalSection(crit
);
132 if (InterlockedIncrement( &crit
->LockCount
))
134 if (crit
->OwningThread
== GetCurrentThreadId())
136 crit
->RecursionCount
++;
139 /* Now wait for it */
140 if (crit
->LockSemaphore
)
142 WAIT_STRUCT
*wait
= &THREAD_Current()->wait_struct
;
145 wait
->signaled
= WAIT_FAILED
;
146 wait
->wait_all
= FALSE
;
147 wait
->objs
[0] = (K32OBJ
*)crit
->LockSemaphore
;
148 K32OBJ_IncCount( wait
->objs
[0] );
149 SYNC_WaitForCondition( wait
, INFINITE32
);
150 K32OBJ_DecCount( wait
->objs
[0] );
153 else if (crit
->Reserved
!= (DWORD
)-1)
159 sop
.sem_flg
= 0/*SEM_UNDO*/;
162 ret
= semop( (int)crit
->Reserved
, &sop
, 1 );
163 } while ((ret
== -1) && (errno
== EINTR
));
167 MSG( "Uninitialized critical section (%p)\n", crit
);
171 crit
->OwningThread
= GetCurrentThreadId();
172 crit
->RecursionCount
= 1;
176 /***********************************************************************
177 * TryEnterCriticalSection (KERNEL32.898) (NTDLL.969)
179 BOOL32 WINAPI
TryEnterCriticalSection( CRITICAL_SECTION
*crit
)
181 if (InterlockedIncrement( &crit
->LockCount
))
183 if (crit
->OwningThread
== GetCurrentThreadId())
185 crit
->RecursionCount
++;
188 /* FIXME: this doesn't work */
189 InterlockedDecrement( &crit
->LockCount
);
192 crit
->OwningThread
= GetCurrentThreadId();
193 crit
->RecursionCount
= 1;
198 /***********************************************************************
199 * LeaveCriticalSection (KERNEL32.494) (NTDLL.426)
201 void WINAPI
LeaveCriticalSection( CRITICAL_SECTION
*crit
)
203 if (crit
->OwningThread
!= GetCurrentThreadId()) return;
205 if (--crit
->RecursionCount
)
207 InterlockedDecrement( &crit
->LockCount
);
210 crit
->OwningThread
= 0;
211 if (InterlockedDecrement( &crit
->LockCount
) >= 0)
213 /* Someone is waiting */
214 if (crit
->LockSemaphore
)
216 CRIT_SECTION
*obj
= (CRIT_SECTION
*)crit
->LockSemaphore
;
218 obj
->signaled
= TRUE
;
219 SYNC_WakeUp( &obj
->wait_queue
, 1 );
222 else if (crit
->Reserved
!= (DWORD
)-1)
227 sop
.sem_flg
= 0/*SEM_UNDO*/;
228 semop( (int)crit
->Reserved
, &sop
, 1 );
234 /***********************************************************************
235 * MakeCriticalSectionGlobal (KERNEL32.515)
237 void WINAPI
MakeCriticalSectionGlobal( CRITICAL_SECTION
*crit
)
239 /* Nothing to do: a critical section is always global */
243 /***********************************************************************
244 * ReinitializeCriticalSection (KERNEL32.581)
246 void WINAPI
ReinitializeCriticalSection( CRITICAL_SECTION
*crit
)
248 DeleteCriticalSection( crit
);
249 InitializeCriticalSection( crit
);
253 /***********************************************************************
254 * CRIT_SECTION_Signaled
256 static BOOL32
CRIT_SECTION_Signaled( K32OBJ
*obj
, DWORD thread_id
)
258 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
259 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
260 return crit
->signaled
;
264 /***********************************************************************
265 * CRIT_SECTION_Satisfied
267 * Wait on this object has been satisfied.
269 static BOOL32
CRIT_SECTION_Satisfied( K32OBJ
*obj
, DWORD thread_id
)
271 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
272 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
273 /* Only one thread is allowed to wake up */
274 crit
->signaled
= FALSE
;
275 return FALSE
; /* Not abandoned */
279 /***********************************************************************
280 * CRIT_SECTION_AddWait
282 * Add thread to object wait queue.
284 static void CRIT_SECTION_AddWait( K32OBJ
*obj
, DWORD thread_id
)
286 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
287 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
288 THREAD_AddQueue( &crit
->wait_queue
, THREAD_ID_TO_THDB(thread_id
) );
292 /***********************************************************************
293 * CRIT_SECTION_RemoveWait
295 * Remove current thread from object wait queue.
297 static void CRIT_SECTION_RemoveWait( K32OBJ
*obj
, DWORD thread_id
)
299 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
300 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
301 THREAD_RemoveQueue( &crit
->wait_queue
, THREAD_ID_TO_THDB(thread_id
) );
305 /***********************************************************************
306 * CRIT_SECTION_Destroy
308 static void CRIT_SECTION_Destroy( K32OBJ
*obj
)
310 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
311 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
312 /* There cannot be any thread on the list since the ref count is 0 */
313 assert( crit
->wait_queue
== NULL
);
314 obj
->type
= K32OBJ_UNKNOWN
;
315 HeapFree( SystemHeap
, 0, crit
);