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