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 */
55 CRIT_SECTION_Destroy
/* destroy */
58 /***********************************************************************
59 * InitializeCriticalSection (KERNEL32.472) (NTDLL.406)
61 void WINAPI
InitializeCriticalSection( CRITICAL_SECTION
*crit
)
66 crit
->RecursionCount
= 0;
67 crit
->OwningThread
= 0;
68 crit
->LockSemaphore
= 0;
71 if (!(obj
= (CRIT_SECTION
*)HeapAlloc( SystemHeap
, 0, sizeof(*obj
) )))
72 return; /* No way to return an error... */
73 obj
->header
.type
= K32OBJ_CRITICAL_SECTION
;
74 obj
->header
.refcount
= 1;
75 obj
->wait_queue
= NULL
;
76 obj
->signaled
= FALSE
;
77 crit
->LockSemaphore
= (HANDLE32
)obj
;
78 crit
->Reserved
= (DWORD
)-1;
83 crit
->Reserved
= (DWORD
)semget( IPC_PRIVATE
, 1, IPC_CREAT
| 0777 );
84 if (crit
->Reserved
== (DWORD
)-1)
90 semctl( (int)crit
->Reserved
, 0, SETVAL
, val
);
95 /***********************************************************************
96 * DeleteCriticalSection (KERNEL32.185) (NTDLL.327)
98 void WINAPI
DeleteCriticalSection( CRITICAL_SECTION
*crit
)
100 CRIT_SECTION
*obj
= (CRIT_SECTION
*)crit
->LockSemaphore
;
104 if (crit
->RecursionCount
) /* Should not happen */
105 fprintf( stderr
, "Deleting owned critical section (%p)\n", crit
);
106 crit
->LockCount
= -1;
107 crit
->RecursionCount
= 0;
108 crit
->OwningThread
= 0;
109 crit
->LockSemaphore
= 0;
110 K32OBJ_DecCount( &obj
->header
);
112 else if (crit
->Reserved
!= (DWORD
)-1)
114 semctl( (int)crit
->Reserved
, 0, IPC_RMID
, (union semun
)0 );
119 /***********************************************************************
120 * EnterCriticalSection (KERNEL32.195) (NTDLL.344)
122 void WINAPI
EnterCriticalSection( CRITICAL_SECTION
*crit
)
124 if (InterlockedIncrement( &crit
->LockCount
))
126 if (crit
->OwningThread
== GetCurrentThreadId())
128 crit
->RecursionCount
++;
131 /* Now wait for it */
132 if (crit
->LockSemaphore
)
134 WAIT_STRUCT
*wait
= &THREAD_Current()->wait_struct
;
137 wait
->signaled
= WAIT_FAILED
;
138 wait
->wait_all
= FALSE
;
139 wait
->objs
[0] = (K32OBJ
*)crit
->LockSemaphore
;
140 K32OBJ_IncCount( wait
->objs
[0] );
141 SYNC_WaitForCondition( wait
, INFINITE32
);
142 K32OBJ_DecCount( wait
->objs
[0] );
145 else if (crit
->Reserved
!= (DWORD
)-1)
151 sop
.sem_flg
= SEM_UNDO
;
154 ret
= semop( (int)crit
->Reserved
, &sop
, 1 );
155 } while ((ret
== -1) && (errno
== EINTR
));
159 fprintf( stderr
, "Uninitialized critical section (%p)\n", crit
);
163 crit
->OwningThread
= GetCurrentThreadId();
164 crit
->RecursionCount
= 1;
168 /***********************************************************************
169 * TryEnterCriticalSection (KERNEL32.898) (NTDLL.969)
171 BOOL32 WINAPI
TryEnterCriticalSection( CRITICAL_SECTION
*crit
)
173 if (InterlockedIncrement( &crit
->LockCount
))
175 if (crit
->OwningThread
== GetCurrentThreadId())
177 crit
->RecursionCount
++;
180 /* FIXME: this doesn't work */
181 InterlockedDecrement( &crit
->LockCount
);
184 crit
->OwningThread
= GetCurrentThreadId();
185 crit
->RecursionCount
= 1;
190 /***********************************************************************
191 * LeaveCriticalSection (KERNEL32.494) (NTDLL.426)
193 void WINAPI
LeaveCriticalSection( CRITICAL_SECTION
*crit
)
195 if (crit
->OwningThread
!= GetCurrentThreadId()) return;
197 if (--crit
->RecursionCount
)
199 InterlockedDecrement( &crit
->LockCount
);
202 crit
->OwningThread
= 0;
203 if (InterlockedDecrement( &crit
->LockCount
) >= 0)
205 /* Someone is waiting */
206 if (crit
->LockSemaphore
)
208 CRIT_SECTION
*obj
= (CRIT_SECTION
*)crit
->LockSemaphore
;
210 obj
->signaled
= TRUE
;
211 SYNC_WakeUp( &obj
->wait_queue
, 1 );
214 else if (crit
->Reserved
!= (DWORD
)-1)
219 sop
.sem_flg
= SEM_UNDO
;
220 semop( (int)crit
->Reserved
, &sop
, 1 );
226 /***********************************************************************
227 * MakeCriticalSectionGlobal (KERNEL32.515)
229 void WINAPI
MakeCriticalSectionGlobal( CRITICAL_SECTION
*crit
)
231 /* Nothing to do: a critical section is always global */
235 /***********************************************************************
236 * ReinitializeCriticalSection (KERNEL32.581)
238 void WINAPI
ReinitializeCriticalSection( CRITICAL_SECTION
*crit
)
240 DeleteCriticalSection( crit
);
241 InitializeCriticalSection( crit
);
245 /***********************************************************************
246 * CRIT_SECTION_Signaled
248 static BOOL32
CRIT_SECTION_Signaled( K32OBJ
*obj
, DWORD thread_id
)
250 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
251 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
252 return crit
->signaled
;
256 /***********************************************************************
257 * CRIT_SECTION_Satisfied
259 * Wait on this object has been satisfied.
261 static BOOL32
CRIT_SECTION_Satisfied( K32OBJ
*obj
, DWORD thread_id
)
263 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
264 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
265 /* Only one thread is allowed to wake up */
266 crit
->signaled
= FALSE
;
267 return FALSE
; /* Not abandoned */
271 /***********************************************************************
272 * CRIT_SECTION_AddWait
274 * Add thread to object wait queue.
276 static void CRIT_SECTION_AddWait( K32OBJ
*obj
, DWORD thread_id
)
278 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
279 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
280 THREAD_AddQueue( &crit
->wait_queue
, THREAD_ID_TO_THDB(thread_id
) );
284 /***********************************************************************
285 * CRIT_SECTION_RemoveWait
287 * Remove current thread from object wait queue.
289 static void CRIT_SECTION_RemoveWait( K32OBJ
*obj
, DWORD thread_id
)
291 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
292 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
293 THREAD_RemoveQueue( &crit
->wait_queue
, THREAD_ID_TO_THDB(thread_id
) );
297 /***********************************************************************
298 * CRIT_SECTION_Destroy
300 static void CRIT_SECTION_Destroy( K32OBJ
*obj
)
302 CRIT_SECTION
*crit
= (CRIT_SECTION
*)obj
;
303 assert( obj
->type
== K32OBJ_CRITICAL_SECTION
);
304 /* There cannot be any thread on the list since the ref count is 0 */
305 assert( crit
->wait_queue
== NULL
);
306 obj
->type
= K32OBJ_UNKNOWN
;
307 HeapFree( SystemHeap
, 0, crit
);