cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
semaphore.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Semaphores and Mutexes *
4 * Copyright Peter Gutmann 1997-2005 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "acl.h"
11  #include "kernel.h"
12 #else
13  #include "crypt.h"
14  #include "kernel/acl.h"
15  #include "kernel/kernel.h"
16 #endif /* Compiler-specific includes */
17 
18 /* A pointer to the kernel data block */
19 
20 static KERNEL_DATA *krnlData = NULL;
21 
22 /****************************************************************************
23 * *
24 * Init/Shutdown Functions *
25 * *
26 ****************************************************************************/
27 
28 /* A template to initialise the semaphore table */
29 
30 static const SEMAPHORE_INFO SEMAPHORE_INFO_TEMPLATE = \
31  { SEMAPHORE_STATE_UNINITED, 0, 0 };
32 
33 /* Create and destroy the semaphores and mutexes. Since mutexes usually
34  aren't scalar values and are declared and accessed via macros that
35  manipulate various fields, we have to handle a pile of them individually
36  rather than using an array of mutexes */
37 
39 int initSemaphores( INOUT KERNEL_DATA *krnlDataPtr )
40  {
41  int i, status;
42 
43  assert( isWritePtr( krnlDataPtr, sizeof( KERNEL_DATA ) ) );
44 
45  static_assert( MUTEX_LAST == 4, "Mutex value" );
46 
47  /* Set up the reference to the kernel data block */
48  krnlData = krnlDataPtr;
49 
50  /* Clear the semaphore table */
51  for( i = 0; i < SEMAPHORE_LAST; i++ )
52  krnlData->semaphoreInfo[ i ] = SEMAPHORE_INFO_TEMPLATE;
53 
54  /* Initialize any data structures required to make the semaphore table
55  thread-safe */
56  MUTEX_CREATE( semaphore, status );
57  ENSURES( cryptStatusOK( status ) );
58 
59  /* Initialize the mutexes */
60  MUTEX_CREATE( mutex1, status );
61  ENSURES( cryptStatusOK( status ) );
62  MUTEX_CREATE( mutex2, status );
63  ENSURES( cryptStatusOK( status ) );
64  MUTEX_CREATE( mutex3, status );
65  ENSURES( cryptStatusOK( status ) );
66 
67  return( CRYPT_OK );
68  }
69 
70 void endSemaphores( void )
71  {
72  REQUIRES_V( ( krnlData->initLevel == INIT_LEVEL_KRNLDATA && \
73  krnlData->shutdownLevel == SHUTDOWN_LEVEL_NONE ) || \
74  ( krnlData->initLevel == INIT_LEVEL_KRNLDATA && \
75  krnlData->shutdownLevel == SHUTDOWN_LEVEL_MESSAGES ) || \
76  ( krnlData->initLevel == INIT_LEVEL_FULL && \
77  krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MESSAGES ) );
78 
79  /* Signal that kernel mechanisms are no longer available */
81 
82  /* Shut down the mutexes */
83  MUTEX_DESTROY( mutex3);
84  MUTEX_DESTROY( mutex2 );
85  MUTEX_DESTROY( mutex1 );
86 
87  /* Destroy any data structures required to make the semaphore table
88  thread-safe */
90  }
91 
92 /****************************************************************************
93 * *
94 * Semaphore Functions *
95 * *
96 ****************************************************************************/
97 
98 /* Under multithreaded OSes, we often need to wait for certain events before
99  we can continue (for example when asynchronously accessing system
100  objects anything that depends on the object being available needs to
101  wait for the access to complete) or handle mutual exclusion when accessing
102  a shared resource. The following functions abstract this handling,
103  providing a lightweight semaphore mechanism via mutexes, which is used
104  before checking a system synchronisation object (mutexes usually don't
105  require a kernel entry, while semaphores usually do). The semaphore
106  function works a bit like the Win32 Enter/LeaveCriticalSection()
107  routines, which perform a quick check on a user-level lock and only call
108  the kernel-level handler if necessary (in most cases this isn't
109  necessary). A useful side-effect is that since they work with
110  lightweight local locks instead of systemwide locking objects, they
111  aren't vulnerable to security problems where (for example) another
112  process can mess with a globally visible object handle. This is
113  particularly problematic under Windows, where (for example) CreateMutex()
114  can return a handle to an already-existing object of the same name rather
115  than a newly-created object (there's no O_EXCL functionality).
116 
117  Semaphores are one-shots, so that once set and cleared they can't be
118  reset. This is handled by enforcing the following state transitions:
119 
120  Uninited -> Set | Clear
121  Set -> Set | Clear
122  Clear -> Clear
123 
124  The handling is complicated somewhat by the fact that on some systems the
125  semaphore has to be explicitly deleted, but only the last thread to use it
126  can safely delete it. In order to handle this, we reference-count the
127  semaphore and let the last thread out delete it. This is handled by
128  introducing an additional state preClear, which indicates that while the
129  semaphore object is still present, the last thread out should delete it,
130  bringing it to the true clear state */
131 
132 void setSemaphore( IN_ENUM( SEMAPHORE ) const SEMAPHORE_TYPE semaphore,
133  const MUTEX_HANDLE object )
134  {
135  SEMAPHORE_INFO *semaphoreInfo;
136 
137  REQUIRES_V( semaphore > SEMAPHORE_NONE && semaphore < SEMAPHORE_LAST );
138 
139  /* It's safe to get a pointer to this outside the lock, we just can't
140  access it yet */
141  semaphoreInfo = &krnlData->semaphoreInfo[ semaphore ];
142 
143  /* Lock the semaphore table, set the semaphore, and unlock it again */
144  MUTEX_LOCK( semaphore );
145  if( semaphoreInfo->state == SEMAPHORE_STATE_UNINITED )
146  {
147  /* The semaphore can only be set if it's currently in the uninited
148  state. Since the semaphore handle may be a non-scalar type we
149  have to use a cast to make it non-const (semaphoreInfo->object
150  can be const if it's a pointer but has to be non-const if it's
151  a scalar) */
152  *semaphoreInfo = SEMAPHORE_INFO_TEMPLATE;
153  semaphoreInfo->state = SEMAPHORE_STATE_SET;
154  semaphoreInfo->object = ( MUTEX_HANDLE ) object;
155  }
156  MUTEX_UNLOCK( semaphore );
157  }
158 
159 void clearSemaphore( IN_ENUM( SEMAPHORE ) const SEMAPHORE_TYPE semaphore )
160  {
161  SEMAPHORE_INFO *semaphoreInfo;
162 
163  REQUIRES_V( semaphore > SEMAPHORE_NONE && semaphore < SEMAPHORE_LAST );
164 
165  /* It's safe to get a pointer to this outside the lock, we just can't
166  access it yet */
167  semaphoreInfo = &krnlData->semaphoreInfo[ semaphore ];
168 
169  /* Lock the semaphore table, clear the semaphore, and unlock it again */
170  MUTEX_LOCK( semaphore );
171  if( semaphoreInfo->state == SEMAPHORE_STATE_SET )
172  {
173  /* Precondition: The reference count is valid. Note that we have to
174  make this an assert() rather than a REQUIRES() because the latter
175  would exit with the semaphore still held */
176 #if !( defined( __WINCE__ ) && _WIN32_WCE < 400 )
177  assert( semaphoreInfo[ semaphore ].refCount >= 0 );
178 #endif /* Fix for bug in PocketPC 2002 emulator with eVC++ 3.0 */
179 
180  /* If there are threads waiting on this semaphore, tell the last
181  thread out to turn out the lights */
182  if( semaphoreInfo->refCount > 0 )
183  semaphoreInfo->state = SEMAPHORE_STATE_PRECLEAR;
184  else
185  {
186  /* No threads waiting on the semaphore, we can delete it */
187  THREAD_CLOSE( semaphoreInfo->object );
188  *semaphoreInfo = SEMAPHORE_INFO_TEMPLATE;
189  }
190  }
191  MUTEX_UNLOCK( semaphore );
192  }
193 
194 /* Wait on a semaphore. This occurs in two phases, first we extract the
195  information that we need from the semaphore table, then we unlock it and
196  wait on the semaphore if necessary. This is necessary because the wait
197  can take an indeterminate amount of time and we don't want to tie up the
198  other semaphores while this occurs. Note that this type of waiting on
199  local (rather than system) semaphores where possible greatly improves
200  performance, in some cases the wait on a signalled system semaphore can
201  take several seconds whereas waiting on the local semaphore only takes a
202  few ms. Once the wait has completed, we update the semaphore state as
203  per the longer description above */
204 
205 CHECK_RETVAL_BOOL \
206 BOOLEAN krnlWaitSemaphore( IN_ENUM( SEMAPHORE ) const SEMAPHORE_TYPE semaphore )
207  {
208  SEMAPHORE_INFO *semaphoreInfo;
210  BOOLEAN semaphoreSet = FALSE;
211  int status = CRYPT_OK;
212 
213  REQUIRES_B( semaphore > SEMAPHORE_NONE && semaphore < SEMAPHORE_LAST );
214 
215  /* If we're in a shutdown and the semaphores have been destroyed, don't
216  try and acquire the semaphore mutex. In this case anything that
217  they're protecting should be set to a shutdown state in which any
218  access fails, so this isn't a problem */
219  if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MUTEXES )
220  return( FALSE );
221 
222  /* Lock the semaphore table, extract the information that we need, and
223  unlock it again */
224  semaphoreInfo = &krnlData->semaphoreInfo[ semaphore ];
225  MUTEX_LOCK( semaphore );
226  if( semaphoreInfo->state == SEMAPHORE_STATE_SET )
227  {
228  /* Precondition: The reference count is valid. Note that we have to
229  make this an assert() rather than a REQUIRES() because the latter
230  would exit with the semaphore still held */
231  assert( semaphoreInfo->refCount >= 0 );
232 
233  /* The semaphore is set and not in use, extract the information we
234  require and mark is as being in use */
235  object = semaphoreInfo->object;
236  semaphoreInfo->refCount++;
237  semaphoreSet = TRUE;
238  }
239  MUTEX_UNLOCK( semaphore );
240 
241  /* If the semaphore wasn't set or is in use, exit now */
242  if( !semaphoreSet )
243  return( TRUE );
244 
245  /* Wait on the object */
246  assert( memcmp( &object, &SEMAPHORE_INFO_TEMPLATE.object,
247  sizeof( MUTEX_HANDLE ) ) );
248  THREAD_WAIT( object, status );
249  if( cryptStatusError( status ) )
250  {
251  DEBUG_DIAG(( "Wait on object failed" ));
252  assert( DEBUG_WARN );
253  return( FALSE );
254  }
255 
256  /* Lock the semaphore table, update the information, and unlock it
257  again */
258  MUTEX_LOCK( semaphore );
259  if( semaphoreInfo->state == SEMAPHORE_STATE_SET || \
260  semaphoreInfo->state == SEMAPHORE_STATE_PRECLEAR )
261  {
262  /* The semaphore is still set, update the reference count */
263  semaphoreInfo->refCount--;
264 
265  /* Inner precondition: The reference count is valid. Note that we
266  have to make this an assert() rather than a REQUIRES() because
267  the latter would exit with the semaphore still held */
268  assert( semaphoreInfo->refCount >= 0 );
269 
270  /* If the object owner has signalled that it's done with the object
271  and the reference count has reached zero, we can delete it */
272  if( semaphoreInfo->state == SEMAPHORE_STATE_PRECLEAR || \
273  semaphoreInfo->refCount <= 0 )
274  {
275  /* No threads waiting on the semaphore, we can delete it */
276  THREAD_CLOSE( object );
277  *semaphoreInfo = SEMAPHORE_INFO_TEMPLATE;
278  }
279  }
280  MUTEX_UNLOCK( semaphore );
281 
282  return( TRUE );
283  }
284 
285 /****************************************************************************
286 * *
287 * Mutex Functions *
288 * *
289 ****************************************************************************/
290 
291 /* Enter and exit a mutex */
292 
293 CHECK_RETVAL \
294 int krnlEnterMutex( IN_ENUM( MUTEX ) const MUTEX_TYPE mutex )
295  {
296  REQUIRES( mutex > MUTEX_NONE && mutex < MUTEX_LAST );
297 
298  /* If we're in a shutdown and the mutexes have been destroyed, don't
299  try and acquire them. In this case anything that they're protecting
300  should be set to a shutdown state in which any access fails, so this
301  isn't a problem */
302  if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MUTEXES )
303  return( CRYPT_ERROR_PERMISSION );
304 
305  switch( mutex )
306  {
307  case MUTEX_SCOREBOARD:
308  MUTEX_LOCK( mutex1 );
309  break;
310 
311  case MUTEX_SOCKETPOOL:
312  MUTEX_LOCK( mutex2 );
313  break;
314 
315  case MUTEX_RANDOM:
316  MUTEX_LOCK( mutex3 );
317  break;
318 
319  default:
320  retIntError();
321  }
322 
323  return( CRYPT_OK );
324  }
325 
326 void krnlExitMutex( IN_ENUM( MUTEX ) const MUTEX_TYPE mutex )
327  {
328  REQUIRES_V( mutex > MUTEX_NONE && mutex < MUTEX_LAST );
329 
330  /* If we're in a shutdown and the mutexes have been destroyed, don't
331  try and acquire them. In this case anything that they're protecting
332  should be set to a shutdown state in which any access fails, so this
333  isn't a problem */
334  if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MUTEXES )
335  return;
336 
337  switch( mutex )
338  {
339  case MUTEX_SCOREBOARD:
340  MUTEX_UNLOCK( mutex1 );
341  break;
342 
343  case MUTEX_SOCKETPOOL:
344  MUTEX_UNLOCK( mutex2 );
345  break;
346 
347  case MUTEX_RANDOM:
348  MUTEX_UNLOCK( mutex3 );
349  break;
350 
351  default:
353  }
354  }