1 /*
2  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6 
7 #include "native_client/src/shared/platform/nacl_check.h"
8 #include "native_client/src/shared/platform/win/nacl_fast_mutex.h"
9 #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
10 
11 /*
12  * Windows CRITICAL_SECTION objects are recursive locks.
13  * NaClFastMutex should be binary mutexes.  Thus, we keep a flag
14  * is_held to specify whether or not the lock is held.  Only the
15  * thread holding the CRITICAL_SECTION could take the lock again via
16  * EnterCriticalSection, so only that thread could observe a non-zero
17  * value of is_held.  When that occurs, it is because of a recursive
18  * lock acquisition; we crash the app when this occurs.
19  *
20  * If a CRITICAL_SECTION is abandoned, i.e., the thread holding it
21  * exits, MSDN says that the state of the CRITICAL_SECTION is
22  * undefined.  Ignoring standards/legalese interpretations that
23  * include melting the CPU, reasonable implementation-defined behavior
24  * include:
25  *
26  * - leaving the lock held, keeping all other threads from entering;
27  *
28  * - implicitly dropping the lock, letting another thread enter.
29  *
30  * In the first case, the application deadlocks.  This is fine (though
31  * crashing would be better).  In the second case, we will see is_held
32  * set and crash.  This is also reasonable.
33  */
34 
NaClFastMutexCtor(struct NaClFastMutex * flp)35 int NaClFastMutexCtor(struct NaClFastMutex *flp) {
36   flp->is_held = 0;
37   InitializeCriticalSection(&flp->mu);
38   return 1;
39 }
40 
NaClFastMutexDtor(struct NaClFastMutex * flp)41 void NaClFastMutexDtor(struct NaClFastMutex *flp) {
42   CHECK(0 == flp->is_held);
43   DeleteCriticalSection(&flp->mu);
44 }
45 
NaClFastMutexLock(struct NaClFastMutex * flp)46 void NaClFastMutexLock(struct NaClFastMutex *flp) {
47   EnterCriticalSection(&flp->mu);
48   /*
49    * CRITICAL_SECTION locks are recursive lock, but we only want
50    * binary locks.  TODO(bsy): consider returning other error code,
51    * e.g., EDEADLK, here instead.
52    */
53   CHECK(0 == flp->is_held);
54   flp->is_held = 1;
55 }
56 
NaClFastMutexTryLock(struct NaClFastMutex * flp)57 int NaClFastMutexTryLock(struct NaClFastMutex *flp) {
58   if (TryEnterCriticalSection(&flp->mu)) {
59     /*
60      * Abandoned critical sections state is undefined.  TODO(bsy):
61      * consider returning other error code, e.g., EDEADLK here.
62      */
63     CHECK(0 == flp->is_held);
64     flp->is_held = 1;
65     return 0;
66   }
67   /*
68    * Abandoned critical sections state is undefined; cannot check that
69    * is_held is true without holding the lock, so this might actually
70    * be a deadlock.
71    */
72   return NACL_ABI_EBUSY;
73 }
74 
NaClFastMutexUnlock(struct NaClFastMutex * flp)75 void NaClFastMutexUnlock(struct NaClFastMutex *flp) {
76   CHECK(1 == flp->is_held);
77   flp->is_held = 0;
78   LeaveCriticalSection(&flp->mu);
79 }
80