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 : /*
8 : * C bindings for C++ implementation of synchronization objects
9 : * (based on Chrome code)
10 : */
11 :
12 : /* Beware: there is a delicate requirement here that the untrusted code be able
13 : * to include nacl_abi_* type definitions. These headers share an include
14 : * guard with the exported versions, which get included first. Unfortunately,
15 : * tying them to different include guards causes multiple definitions of
16 : * macros.
17 : */
18 : #include "native_client/src/include/portability.h"
19 : #include <sys/types.h>
20 : #include <sys/timeb.h>
21 :
22 : #include "native_client/src/include/nacl_macros.h"
23 :
24 : #include "native_client/src/shared/platform/nacl_sync.h"
25 :
26 : #include "native_client/src/shared/platform/nacl_log.h"
27 : #include "native_client/src/shared/platform/nacl_time.h"
28 : #include "native_client/src/shared/platform/win/condition_variable.h"
29 : #include "native_client/src/shared/platform/win/lock.h"
30 : #include "native_client/src/trusted/service_runtime/include/sys/time.h"
31 :
32 : /* Mutex */
33 28 : int NaClMutexCtor(struct NaClMutex *mp) {
34 28 : mp->lock = new NaCl::Lock();
35 28 : mp->held = 0;
36 28 : return NULL != mp->lock;
37 28 : }
38 :
39 23 : void NaClMutexDtor(struct NaClMutex *mp) {
40 23 : delete reinterpret_cast<NaCl::Lock *>(mp->lock);
41 23 : mp->lock = NULL;
42 23 : }
43 :
44 28 : NaClSyncStatus NaClMutexLock(struct NaClMutex *mp) {
45 28 : reinterpret_cast<NaCl::Lock *>(mp->lock)->Acquire();
46 28 : if (!mp->held) {
47 28 : mp->held = 1;
48 28 : return NACL_SYNC_OK;
49 : } else {
50 : /*
51 : * The only way we can successfully Acquire but have mp->held
52 : * already be true is because this is a recursive lock
53 : * acquisition. With binary mutexes, this is a trivial deadlock.
54 : * Simulate the deadlock.
55 : */
56 : struct nacl_abi_timespec long_time;
57 :
58 1 : long_time.tv_sec = 10000;
59 1 : long_time.tv_nsec = 0;
60 : /*
61 : * Note that NaClLog uses mutexes internally, so this log message
62 : * assumes that this error is not being triggered from there. The
63 : * service runtime should not deadlock in this way -- only
64 : * untrusted user code might. In any case, this is "safe" in that
65 : * even if the NaClLog module were to have this bug, it would
66 : * result in an infinite log spew -- something that ought to be
67 : * quickly detected in normal testing.
68 : */
69 : NaClLog(LOG_WARNING,
70 : ("NaClMutexLock: recursive lock of binary mutex."
71 1 : " Deadlock being simulated\n"));
72 : for (;;) {
73 1 : NaClNanosleep(&long_time, NULL);
74 0 : }
75 : }
76 28 : }
77 :
78 1 : NaClSyncStatus NaClMutexTryLock(struct NaClMutex *mp) {
79 : NaClSyncStatus status = reinterpret_cast<NaCl::Lock *>(mp->lock)->Try() ?
80 1 : NACL_SYNC_OK : NACL_SYNC_BUSY;
81 1 : if (status == NACL_SYNC_OK) {
82 1 : if (mp->held) {
83 : /* decrement internal recursion count in the underlying lock */
84 1 : reinterpret_cast<NaCl::Lock *>(mp->lock)->Release();
85 1 : status = NACL_SYNC_BUSY;
86 : }
87 1 : mp->held = 1;
88 : }
89 1 : return status;
90 1 : }
91 :
92 28 : NaClSyncStatus NaClMutexUnlock(struct NaClMutex *mp) {
93 28 : mp->held = 0;
94 28 : reinterpret_cast<NaCl::Lock *>(mp->lock)->Release();
95 28 : return NACL_SYNC_OK;
96 28 : }
97 :
98 : /* Condition variable */
99 :
100 2 : int NaClCondVarCtor(struct NaClCondVar *cvp) {
101 2 : cvp->cv = new NaCl::ConditionVariable();
102 2 : return 1;
103 2 : }
104 :
105 2 : void NaClCondVarDtor(struct NaClCondVar *cvp) {
106 2 : delete reinterpret_cast<NaCl::ConditionVariable*>(cvp->cv);
107 2 : }
108 :
109 2 : NaClSyncStatus NaClCondVarSignal(struct NaClCondVar *cvp) {
110 2 : reinterpret_cast<NaCl::ConditionVariable*>(cvp->cv)->Signal();
111 2 : return NACL_SYNC_OK;
112 2 : }
113 :
114 0 : NaClSyncStatus NaClCondVarBroadcast(struct NaClCondVar *cvp) {
115 0 : reinterpret_cast<NaCl::ConditionVariable*>(cvp->cv)->Broadcast();
116 0 : return NACL_SYNC_OK;
117 0 : }
118 :
119 : NaClSyncStatus NaClCondVarWait(struct NaClCondVar *cvp,
120 2 : struct NaClMutex *mp) {
121 2 : mp->held = 0;
122 : reinterpret_cast<NaCl::ConditionVariable*>(cvp->cv)->Wait(
123 2 : *(reinterpret_cast<NaCl::Lock *>(mp->lock)));
124 2 : mp->held = 1;
125 2 : return NACL_SYNC_OK;
126 2 : }
127 :
128 : NaClSyncStatus NaClCondVarTimedWaitRelative(
129 : struct NaClCondVar *cvp,
130 : struct NaClMutex *mp,
131 0 : struct nacl_abi_timespec const *reltime) {
132 : NaCl::TimeDelta relative_wait(
133 : NaCl::TimeDelta::FromMicroseconds(
134 : reltime->tv_sec
135 : * NaCl::Time::kMicrosecondsPerSecond
136 : + reltime->tv_nsec
137 0 : / NaCl::Time::kNanosecondsPerMicrosecond));
138 : int result;
139 0 : mp->held = 0;
140 : result = (reinterpret_cast<NaCl::ConditionVariable*>(cvp->cv)->TimedWaitRel(
141 : *(reinterpret_cast<NaCl::Lock *>(mp->lock)),
142 0 : relative_wait));
143 0 : mp->held = 1;
144 0 : if (0 == result) {
145 0 : return NACL_SYNC_CONDVAR_TIMEDOUT;
146 : }
147 0 : return NACL_SYNC_OK;
148 0 : }
149 :
150 : NaClSyncStatus NaClCondVarTimedWaitAbsolute(
151 : struct NaClCondVar *cvp,
152 : struct NaClMutex *mp,
153 0 : struct nacl_abi_timespec const *abstime) {
154 : NaCl::TimeTicks ticks(abstime->tv_sec
155 : * NaCl::Time::kMicrosecondsPerSecond
156 : + abstime->tv_nsec
157 0 : / NaCl::Time::kNanosecondsPerMicrosecond);
158 : int result;
159 0 : mp->held = 0;
160 : result = reinterpret_cast<NaCl::ConditionVariable*>(cvp->cv)->TimedWaitAbs(
161 : *(reinterpret_cast<NaCl::Lock *>(mp->lock)),
162 0 : ticks);
163 0 : mp->held = 1;
164 0 : if (0 == result) {
165 0 : return NACL_SYNC_CONDVAR_TIMEDOUT;
166 : }
167 0 : return NACL_SYNC_OK;
168 0 : }
|