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 :
35 9 : int NaClFastMutexCtor(struct NaClFastMutex *flp) {
36 9 : flp->is_held = 0;
37 9 : InitializeCriticalSection(&flp->mu);
38 9 : return 1;
39 9 : }
40 :
41 8 : void NaClFastMutexDtor(struct NaClFastMutex *flp) {
42 8 : CHECK(0 == flp->is_held);
43 8 : DeleteCriticalSection(&flp->mu);
44 8 : }
45 :
46 8 : void NaClFastMutexLock(struct NaClFastMutex *flp) {
47 8 : 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 8 : CHECK(0 == flp->is_held);
54 8 : flp->is_held = 1;
55 8 : }
56 :
57 0 : int NaClFastMutexTryLock(struct NaClFastMutex *flp) {
58 0 : 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 0 : CHECK(0 == flp->is_held);
64 0 : flp->is_held = 1;
65 0 : 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 0 : return NACL_ABI_EBUSY;
73 0 : }
74 :
75 8 : void NaClFastMutexUnlock(struct NaClFastMutex *flp) {
76 8 : CHECK(1 == flp->is_held);
77 8 : flp->is_held = 0;
78 8 : LeaveCriticalSection(&flp->mu);
79 8 : }
|