1 : /*
2 : * Copyright (c) 2011 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 : /*
8 : * NaCl Server Runtime interruptible binary mutex, based on nacl_sync
9 : * interface.
10 : */
11 :
12 : #include "native_client/src/include/portability.h"
13 : #include "native_client/src/shared/platform/nacl_interruptible_mutex.h"
14 : #include "native_client/src/shared/platform/nacl_log.h"
15 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
16 :
17 :
18 0 : int NaClIntrMutexCtor(struct NaClIntrMutex *mp) {
19 0 : if (!NaClMutexCtor(&mp->mu)) {
20 0 : return 0;
21 : }
22 0 : if (!NaClCondVarCtor(&mp->cv)) {
23 0 : NaClMutexDtor(&mp->mu);
24 0 : return 0;
25 : }
26 0 : mp->lock_state = NACL_INTR_LOCK_FREE;
27 0 : return 1;
28 0 : }
29 :
30 0 : void NaClIntrMutexDtor(struct NaClIntrMutex *mp) {
31 0 : NaClCondVarDtor(&mp->cv);
32 0 : NaClMutexDtor(&mp->mu);
33 0 : }
34 :
35 0 : NaClSyncStatus NaClIntrMutexLock(struct NaClIntrMutex *mp) {
36 0 : NaClSyncStatus rv = NACL_SYNC_INTERNAL_ERROR;
37 0 : NaClXMutexLock(&mp->mu);
38 0 : while (NACL_INTR_LOCK_HELD == mp->lock_state) {
39 0 : NaClXCondVarWait(&mp->cv, &mp->mu);
40 0 : }
41 0 : if (NACL_INTR_LOCK_FREE == mp->lock_state) {
42 0 : mp->lock_state = NACL_INTR_LOCK_HELD;
43 0 : rv = NACL_SYNC_OK;
44 0 : }
45 :
46 0 : if (NACL_INTR_LOCK_INTERRUPTED == mp->lock_state) {
47 0 : rv = NACL_SYNC_MUTEX_INTERRUPTED;
48 0 : }
49 0 : NaClXMutexUnlock(&mp->mu);
50 0 : return rv;
51 : }
52 :
53 0 : NaClSyncStatus NaClIntrMutexTryLock(struct NaClIntrMutex *mp) {
54 0 : NaClSyncStatus rv = NACL_SYNC_INTERNAL_ERROR;
55 :
56 0 : NaClXMutexLock(&mp->mu);
57 0 : switch (mp->lock_state) {
58 : case NACL_INTR_LOCK_FREE:
59 0 : mp->lock_state = NACL_INTR_LOCK_HELD;
60 0 : rv = NACL_SYNC_OK;
61 0 : break;
62 : case NACL_INTR_LOCK_HELD:
63 0 : rv = NACL_SYNC_BUSY;
64 0 : break;
65 : case NACL_INTR_LOCK_INTERRUPTED:
66 0 : rv = NACL_SYNC_MUTEX_INTERRUPTED;
67 0 : break;
68 : default:
69 0 : rv = NACL_SYNC_INTERNAL_ERROR;
70 0 : break;
71 : }
72 0 : NaClXMutexUnlock(&mp->mu);
73 0 : return rv;
74 : }
75 :
76 0 : NaClSyncStatus NaClIntrMutexUnlock(struct NaClIntrMutex *mp) {
77 0 : NaClSyncStatus rv = NACL_SYNC_INTERNAL_ERROR;
78 0 : NaClXMutexLock(&mp->mu);
79 0 : if (NACL_INTR_LOCK_HELD != mp->lock_state) {
80 0 : NaClLog(1, "NaClIntrMutxUnlock: unlocking when lock is not held\n");
81 0 : rv = NACL_SYNC_MUTEX_PERMISSION;
82 0 : } else {
83 0 : rv = NACL_SYNC_OK;
84 : }
85 0 : mp->lock_state = NACL_INTR_LOCK_FREE;
86 :
87 0 : NaClXCondVarSignal(&mp->cv);
88 0 : NaClXMutexUnlock(&mp->mu);
89 0 : return rv;
90 : }
91 :
92 0 : void NaClIntrMutexIntr(struct NaClIntrMutex *mp) {
93 0 : NaClXMutexLock(&mp->mu);
94 0 : if (NACL_INTR_LOCK_HELD == mp->lock_state) {
95 : /* potentially there are threads waiting for this thread */
96 0 : mp->lock_state = NACL_INTR_LOCK_INTERRUPTED;
97 0 : NaClXCondVarBroadcast(&mp->cv);
98 0 : } else {
99 0 : mp->lock_state = NACL_INTR_LOCK_INTERRUPTED;
100 : }
101 0 : NaClXMutexUnlock(&mp->mu);
102 0 : }
103 :
104 : /*
105 : * Reset the interruptible mutex, presumably after the condition
106 : * causing the interrupt has been cleared. In our case, this would be
107 : * an E_MOVE_ADDRESS_SPACE induced address space move.
108 : *
109 : * This is safe to invoke only after all threads are known to be in a
110 : * quiescent state -- i.e., will no longer call
111 : * NaClIntrMutex{Try,}Lock on the interruptible mutex -- since there
112 : * is no guarntee that all the threads awaken by NaClIntrMutexIntr
113 : * have actually been run yet.
114 : */
115 0 : void NaClIntrMutexReset(struct NaClIntrMutex *mp) {
116 0 : NaClXMutexLock(&mp->mu);
117 0 : if (NACL_INTR_LOCK_INTERRUPTED != mp->lock_state) {
118 0 : NaClLog(LOG_FATAL,
119 : "NaClIntrMutexReset: lock at 0x%08"NACL_PRIxPTR" not interrupted\n",
120 : (uintptr_t) mp);
121 0 : }
122 0 : mp->lock_state = NACL_INTR_LOCK_FREE;
123 0 : NaClXMutexUnlock(&mp->mu);
124 0 : }
|