- New implementation of SendMessage, ReceiveMessage, ReplyMessage functions
[wine] / scheduler / critsection.c
1 /*
2  * Win32 critical sections
3  *
4  * Copyright 1998 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <sys/sem.h>
12 #include "debug.h"
13 #include "windows.h"
14 #include "winerror.h"
15 #include "winbase.h"
16 #include "heap.h"
17 #include "k32obj.h"
18 #include "debug.h"
19 #include "thread.h"
20
21 /* On some systems this is supposed to be defined in the program */
22 #ifndef HAVE_UNION_SEMUN
23 union semun {
24     int val;
25     struct semid_ds *buf;
26     ushort *array;
27 };
28 #endif
29
30
31 /***********************************************************************
32  *           InitializeCriticalSection   (KERNEL32.472) (NTDLL.406)
33  */
34 void WINAPI InitializeCriticalSection( CRITICAL_SECTION *crit )
35 {
36     crit->LockCount      = -1;
37     crit->RecursionCount = 0;
38     crit->OwningThread   = 0;
39     crit->LockSemaphore  = 0;
40     if (SystemHeap)
41     {
42         crit->LockSemaphore = CreateSemaphore32A( NULL, 0, 1, NULL );
43         crit->Reserved      = (DWORD)-1;
44     }
45     else
46     {
47         union semun val;
48         crit->Reserved = (DWORD)semget( IPC_PRIVATE, 1, IPC_CREAT | 0777 );
49         if (crit->Reserved == (DWORD)-1)
50         {
51             perror( "semget" );
52             return;
53         }
54         val.val = 0;
55         semctl( (int)crit->Reserved, 0, SETVAL, val );
56     }
57 }
58
59
60 /***********************************************************************
61  *           DeleteCriticalSection   (KERNEL32.185) (NTDLL.327)
62  */
63 void WINAPI DeleteCriticalSection( CRITICAL_SECTION *crit )
64 {
65     if (crit->LockSemaphore)
66     {
67         if (crit->RecursionCount)  /* Should not happen */
68             MSG("Deleting owned critical section (%p)\n", crit );
69         crit->LockCount      = -1;
70         crit->RecursionCount = 0;
71         crit->OwningThread   = 0;
72         CloseHandle( crit->LockSemaphore );
73         crit->LockSemaphore  = 0;
74     }
75     else if (crit->Reserved != (DWORD)-1)
76     {
77         semctl( (int)crit->Reserved, 0, IPC_RMID, (union semun)0 );
78     }
79 }
80
81
82 /***********************************************************************
83  *           EnterCriticalSection   (KERNEL32.195) (NTDLL.344)
84  */
85 void WINAPI EnterCriticalSection( CRITICAL_SECTION *crit )
86 {
87     if (        (crit->Reserved==-1) && !(crit->LockSemaphore) &&
88                 (crit!=HEAP_SystemLock)
89     ) {
90         FIXME(win32,"entering uninitialized section(%p)?\n",crit);
91         InitializeCriticalSection(crit);
92     }
93     if (InterlockedIncrement( &crit->LockCount ))
94     {
95         if (crit->OwningThread == GetCurrentThreadId())
96         {
97             crit->RecursionCount++;
98             return;
99         }
100         /* Now wait for it */
101         if (crit->LockSemaphore)
102         {
103             /* FIXME: should set a timeout and raise an exception */
104             WaitForSingleObject( crit->LockSemaphore, INFINITE32 );
105         }
106         else if (crit->Reserved != (DWORD)-1)
107         {
108             int ret;
109             struct sembuf sop;
110             sop.sem_num = 0;
111             sop.sem_op  = -1;
112             sop.sem_flg = 0/*SEM_UNDO*/;
113             do
114             {
115                 ret = semop( (int)crit->Reserved, &sop, 1 );
116             } while ((ret == -1) && (errno == EINTR));
117         }
118         else
119         {
120             MSG( "Uninitialized critical section (%p)\n", crit );
121             return;
122         }
123     }
124     crit->OwningThread   = GetCurrentThreadId();
125     crit->RecursionCount = 1;
126 }
127
128
129 /***********************************************************************
130  *           TryEnterCriticalSection   (KERNEL32.898) (NTDLL.969)
131  */
132 BOOL32 WINAPI TryEnterCriticalSection( CRITICAL_SECTION *crit )
133 {
134     if (InterlockedIncrement( &crit->LockCount ))
135     {
136         if (crit->OwningThread == GetCurrentThreadId())
137         {
138             crit->RecursionCount++;
139             return TRUE;
140         }
141         /* FIXME: this doesn't work */
142         InterlockedDecrement( &crit->LockCount );
143         return FALSE;
144     }
145     crit->OwningThread   = GetCurrentThreadId();
146     crit->RecursionCount = 1;
147     return TRUE;
148 }
149
150
151 /***********************************************************************
152  *           LeaveCriticalSection   (KERNEL32.494) (NTDLL.426)
153  */
154 void WINAPI LeaveCriticalSection( CRITICAL_SECTION *crit )
155 {
156     if (crit->OwningThread != GetCurrentThreadId()) return;
157        
158     if (--crit->RecursionCount)
159     {
160         InterlockedDecrement( &crit->LockCount );
161         return;
162     }
163     crit->OwningThread = 0;
164     if (InterlockedDecrement( &crit->LockCount ) >= 0)
165     {
166         /* Someone is waiting */
167         if (crit->LockSemaphore)
168         {
169             ReleaseSemaphore( crit->LockSemaphore, 1, NULL );
170         }
171         else if (crit->Reserved != (DWORD)-1)
172         {
173             struct sembuf sop;
174             sop.sem_num = 0;
175             sop.sem_op  = 1;
176             sop.sem_flg = 0/*SEM_UNDO*/;
177             semop( (int)crit->Reserved, &sop, 1 );
178         }
179     }
180 }
181
182
183 /***********************************************************************
184  *           MakeCriticalSectionGlobal   (KERNEL32.515)
185  */
186 void WINAPI MakeCriticalSectionGlobal( CRITICAL_SECTION *crit )
187 {
188     crit->LockSemaphore = ConvertToGlobalHandle( crit->LockSemaphore );
189 }
190
191
192 /***********************************************************************
193  *           ReinitializeCriticalSection   (KERNEL32.581)
194  */
195 void WINAPI ReinitializeCriticalSection( CRITICAL_SECTION *crit )
196 {
197     DeleteCriticalSection( crit );
198     InitializeCriticalSection( crit );
199 }