/src/moddable/xs/sources/xsAtomics.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2016-2026 Moddable Tech, Inc. |
3 | | * |
4 | | * This file is part of the Moddable SDK Runtime. |
5 | | * |
6 | | * The Moddable SDK Runtime is free software: you can redistribute it and/or modify |
7 | | * it under the terms of the GNU Lesser General Public License as published by |
8 | | * the Free Software Foundation, either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * The Moddable SDK Runtime is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public License |
17 | | * along with the Moddable SDK Runtime. If not, see <http://www.gnu.org/licenses/>. |
18 | | * |
19 | | */ |
20 | | |
21 | | #include "xsAll.h" |
22 | | |
23 | | static txInteger fxCheckAtomicsIndex(txMachine* the, txInteger index, txInteger length); |
24 | | static txSlot* fxCheckAtomicsTypedArray(txMachine* the, txBoolean onlyInt32); |
25 | | static txSlot* fxCheckAtomicsArrayBuffer(txMachine* the, txSlot* slot, txBoolean onlyShared); |
26 | | static void* fxCheckAtomicsArrayBufferDetached(txMachine* the, txSlot* slot, txBoolean mutable); |
27 | | static txSlot* fxCheckSharedArrayBuffer(txMachine* the, txSlot* slot, txString which); |
28 | | static void fxPushAtomicsValue(txMachine* the, int i, txID id); |
29 | | |
30 | | #define mxAtomicsHead0(TYPE,TO) \ |
31 | 0 | TYPE result = 0; \ |
32 | 0 | txBoolean lock = host->kind == XS_HOST_KIND; \ |
33 | 0 | void* data = (lock) ? host->value.host.data : fxCheckAtomicsArrayBufferDetached(the, host, XS_IMMUTABLE); \ |
34 | 0 | TYPE* address = (TYPE*)(((txByte*)data) + offset) |
35 | | |
36 | | #define mxAtomicsHead1(TYPE,TO) \ |
37 | 0 | TYPE result = 0; \ |
38 | 0 | TYPE value = (TYPE)TO(the, slot); \ |
39 | 0 | txBoolean lock = host->kind == XS_HOST_KIND; \ |
40 | 0 | void* data = (lock) ? host->value.host.data : fxCheckAtomicsArrayBufferDetached(the, host, XS_MUTABLE); \ |
41 | 0 | TYPE* address = (TYPE*)(((txByte*)data) + offset) |
42 | | |
43 | | #define mxAtomicsHead2(TYPE,TO) \ |
44 | 0 | TYPE result = (TYPE)TO(the, slot + 1); \ |
45 | 0 | TYPE value = (TYPE)TO(the, slot); \ |
46 | 0 | txBoolean lock = host->kind == XS_HOST_KIND; \ |
47 | 0 | void* data = (lock) ? host->value.host.data : fxCheckAtomicsArrayBufferDetached(the, host, XS_MUTABLE); \ |
48 | 0 | TYPE* address = (TYPE*)(((txByte*)data) + offset) |
49 | | |
50 | | #ifdef mxUseGCCAtomics |
51 | 0 | #define mxAtomicsCompareExchange() __atomic_compare_exchange(address, &result, &value, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) |
52 | 0 | #define mxAtomicsLoad() __atomic_load(address, &result, __ATOMIC_SEQ_CST) |
53 | 0 | #define mxAtomicsAdd() result = __atomic_fetch_add(address, value, __ATOMIC_SEQ_CST) |
54 | 0 | #define mxAtomicsAnd() result = __atomic_fetch_and(address, value, __ATOMIC_SEQ_CST) |
55 | 0 | #define mxAtomicsExchange() __atomic_exchange(address, &value, &result, __ATOMIC_SEQ_CST) |
56 | 0 | #define mxAtomicsOr() result = __atomic_fetch_or(address, value, __ATOMIC_SEQ_CST) |
57 | 0 | #define mxAtomicsStore() __atomic_store(address, &value, __ATOMIC_SEQ_CST) |
58 | 0 | #define mxAtomicsSub() result = __atomic_fetch_sub(address, value, __ATOMIC_SEQ_CST) |
59 | 0 | #define mxAtomicsXor() result = __atomic_fetch_xor(address, value, __ATOMIC_SEQ_CST) |
60 | | #else |
61 | | #define mxAtomicsCompareExchange() if (lock) fxLockSharedChunk(data); if (*address == result) *address = value; else result = *address; if (lock) fxUnlockSharedChunk(data) |
62 | | #define mxAtomicsLoad() if (lock) fxLockSharedChunk(data); result = *address; if (lock) fxUnlockSharedChunk(data) |
63 | | #define mxAtomicsAdd() if (lock) fxLockSharedChunk(data); result = *address; *address = result + value; if (lock) fxUnlockSharedChunk(data) |
64 | | #define mxAtomicsAnd() if (lock) fxLockSharedChunk(data); result = *address; *address = result & value; if (lock) fxUnlockSharedChunk(data) |
65 | | #define mxAtomicsExchange() if (lock) fxLockSharedChunk(data); result = *address; *address = value; if (lock) fxUnlockSharedChunk(data) |
66 | | #define mxAtomicsOr() if (lock) fxLockSharedChunk(data); result = *address; *address = result | value; if (lock) fxUnlockSharedChunk(data) |
67 | | #define mxAtomicsStore() if (lock) fxLockSharedChunk(data); *address = value; if (lock) fxUnlockSharedChunk(data) |
68 | | #define mxAtomicsSub() if (lock) fxLockSharedChunk(data); result = *address; *address = result - value; if (lock) fxUnlockSharedChunk(data) |
69 | | #define mxAtomicsXor() if (lock) fxLockSharedChunk(data); result = *address; *address = result ^ value; if (lock) fxUnlockSharedChunk(data) |
70 | | #endif |
71 | | |
72 | | #define mxAtomicsTail() \ |
73 | 0 | slot->kind = XS_INTEGER_KIND; \ |
74 | 0 | slot->value.integer = result |
75 | | |
76 | | #define mxAtomicsTailBigInt64() \ |
77 | 0 | fxFromBigInt64(the, slot, result) |
78 | | |
79 | | #define mxAtomicsTailBigUint64() \ |
80 | 0 | fxFromBigUint64(the, slot, result) |
81 | | |
82 | | #define mxAtomicsTailOverflow() \ |
83 | 0 | if (result <= 0x7FFFFFFF) { \ |
84 | 0 | slot->kind = XS_INTEGER_KIND; \ |
85 | 0 | slot->value.integer = result; \ |
86 | 0 | } \ |
87 | 0 | else { \ |
88 | 0 | slot->kind = XS_NUMBER_KIND; \ |
89 | 0 | slot->value.number = result; \ |
90 | 0 | } |
91 | | |
92 | | #define mxAtomicsTailWait() \ |
93 | 0 | return (result != value) ? -1 : (timeout == 0) ? 0 : 1; |
94 | | |
95 | | #define mxAtomicsDeclarations(onlyInt32, onlyShared) \ |
96 | 0 | txSlot* dispatch = fxCheckAtomicsTypedArray(the, onlyInt32); \ |
97 | 0 | txSlot* view = dispatch->next; \ |
98 | 0 | txSlot* buffer = view->next; \ |
99 | 0 | txSlot* host = fxCheckAtomicsArrayBuffer(the, buffer, onlyShared); \ |
100 | 0 | txU2 shift = dispatch->value.typedArray.dispatch->shift; \ |
101 | 0 | txInteger length = fxGetDataViewSize(the, view, buffer) >> shift; \ |
102 | 0 | txInteger index = fxCheckAtomicsIndex(the, 1, length); \ |
103 | 0 | txInteger offset = view->value.dataView.offset + (index << shift) |
104 | | |
105 | 0 | void fxInt8Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS1, fxToInteger); mxAtomicsAdd(); mxAtomicsTail(); } |
106 | 0 | void fxInt16Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS2, fxToInteger); mxAtomicsAdd(); mxAtomicsTail(); } |
107 | 0 | void fxInt32Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsAdd(); mxAtomicsTail(); } |
108 | 0 | void fxInt64Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsAdd(); mxAtomicsTailBigInt64(); } |
109 | 0 | void fxUint8Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU1, fxToUnsigned); mxAtomicsAdd(); mxAtomicsTail(); } |
110 | 0 | void fxUint16Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU2, fxToUnsigned); mxAtomicsAdd(); mxAtomicsTail(); } |
111 | 0 | void fxUint32Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU4, fxToUnsigned); mxAtomicsAdd(); mxAtomicsTailOverflow(); } |
112 | 0 | void fxUint64Add(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU8, fxToBigUint64); mxAtomicsAdd(); mxAtomicsTailBigUint64(); } |
113 | | |
114 | 0 | void fxInt8And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS1, fxToInteger); mxAtomicsAnd(); mxAtomicsTail(); } |
115 | 0 | void fxInt16And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS2, fxToInteger); mxAtomicsAnd(); mxAtomicsTail(); } |
116 | 0 | void fxInt32And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsAnd(); mxAtomicsTail(); } |
117 | 0 | void fxInt64And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsAnd(); mxAtomicsTailBigInt64(); } |
118 | 0 | void fxUint8And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU1, fxToUnsigned); mxAtomicsAnd(); mxAtomicsTail(); } |
119 | 0 | void fxUint16And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU2, fxToUnsigned); mxAtomicsAnd(); mxAtomicsTail(); } |
120 | 0 | void fxUint32And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU4, fxToUnsigned); mxAtomicsAnd(); mxAtomicsTailOverflow(); } |
121 | 0 | void fxUint64And(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU8, fxToBigUint64); mxAtomicsAnd(); mxAtomicsTailBigUint64(); } |
122 | | |
123 | 0 | void fxInt8CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txS1, fxToInteger); mxAtomicsCompareExchange(); mxAtomicsTail(); } |
124 | 0 | void fxInt16CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txS2, fxToInteger); mxAtomicsCompareExchange(); mxAtomicsTail(); } |
125 | 0 | void fxInt32CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txS4, fxToInteger); mxAtomicsCompareExchange(); mxAtomicsTail(); } |
126 | 0 | void fxInt64CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txS8, fxToBigInt64); mxAtomicsCompareExchange(); mxAtomicsTailBigInt64(); } |
127 | 0 | void fxUint8CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txU1, fxToUnsigned); mxAtomicsCompareExchange(); mxAtomicsTail(); } |
128 | 0 | void fxUint16CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txU2, fxToUnsigned); mxAtomicsCompareExchange(); mxAtomicsTail(); } |
129 | 0 | void fxUint32CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txU4, fxToUnsigned); mxAtomicsCompareExchange(); mxAtomicsTailOverflow(); } |
130 | 0 | void fxUint64CompareExchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead2(txU8, fxToBigUint64); mxAtomicsCompareExchange(); mxAtomicsTailBigUint64(); } |
131 | | |
132 | 0 | void fxInt8Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS1, fxToInteger); mxAtomicsExchange(); mxAtomicsTail(); } |
133 | 0 | void fxInt16Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS2, fxToInteger); mxAtomicsExchange(); mxAtomicsTail(); } |
134 | 0 | void fxInt32Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsExchange(); mxAtomicsTail(); } |
135 | 0 | void fxInt64Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsExchange(); mxAtomicsTailBigInt64(); } |
136 | 0 | void fxUint8Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU1, fxToUnsigned); mxAtomicsExchange(); mxAtomicsTail(); } |
137 | 0 | void fxUint16Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU2, fxToUnsigned); mxAtomicsExchange(); mxAtomicsTail(); } |
138 | 0 | void fxUint32Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU4, fxToUnsigned); mxAtomicsExchange(); mxAtomicsTailOverflow(); } |
139 | 0 | void fxUint64Exchange(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU8, fxToBigUint64); mxAtomicsExchange(); mxAtomicsTailBigUint64(); } |
140 | | |
141 | 0 | void fxInt8Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txS1, fxToInteger); mxAtomicsLoad(); mxAtomicsTail(); } |
142 | 0 | void fxInt16Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txS2, fxToInteger); mxAtomicsLoad(); mxAtomicsTail(); } |
143 | 0 | void fxInt32Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txS4, fxToInteger); mxAtomicsLoad(); mxAtomicsTail(); } |
144 | 0 | void fxInt64Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txS8, fxToBigInt64); mxAtomicsLoad(); mxAtomicsTailBigInt64(); } |
145 | 0 | void fxUint8Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txU1, fxToUnsigned); mxAtomicsLoad(); mxAtomicsTail(); } |
146 | 0 | void fxUint16Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txU2, fxToUnsigned); mxAtomicsLoad(); mxAtomicsTail(); } |
147 | 0 | void fxUint32Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txU4, fxToUnsigned); mxAtomicsLoad(); mxAtomicsTailOverflow(); } |
148 | 0 | void fxUint64Load(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead0(txU8, fxToBigUint64); mxAtomicsLoad(); mxAtomicsTailBigUint64(); } |
149 | | |
150 | 0 | void fxInt8Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS1, fxToInteger); mxAtomicsOr(); mxAtomicsTail(); } |
151 | 0 | void fxInt16Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS2, fxToInteger); mxAtomicsOr(); mxAtomicsTail(); } |
152 | 0 | void fxInt32Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsOr(); mxAtomicsTail(); } |
153 | 0 | void fxInt64Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsOr(); mxAtomicsTailBigInt64(); } |
154 | 0 | void fxUint8Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU1, fxToUnsigned); mxAtomicsOr(); mxAtomicsTail(); } |
155 | 0 | void fxUint16Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU2, fxToUnsigned); mxAtomicsOr(); mxAtomicsTail(); } |
156 | 0 | void fxUint32Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU4, fxToUnsigned); mxAtomicsOr(); mxAtomicsTailOverflow(); } |
157 | 0 | void fxUint64Or(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU8, fxToBigUint64); mxAtomicsOr(); mxAtomicsTailBigUint64(); } |
158 | | |
159 | 0 | void fxInt8Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS1, fxToInteger); mxAtomicsStore(); mxAtomicsTail(); } |
160 | 0 | void fxInt16Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS2, fxToInteger); mxAtomicsStore(); mxAtomicsTail(); } |
161 | 0 | void fxInt32Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsStore(); mxAtomicsTail(); } |
162 | 0 | void fxInt64Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsStore(); mxAtomicsTailBigInt64(); } |
163 | 0 | void fxUint8Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU1, fxToUnsigned); mxAtomicsStore(); mxAtomicsTail(); } |
164 | 0 | void fxUint16Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU2, fxToUnsigned); mxAtomicsStore(); mxAtomicsTail(); } |
165 | 0 | void fxUint32Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU4, fxToUnsigned); mxAtomicsStore(); mxAtomicsTailOverflow(); } |
166 | 0 | void fxUint64Store(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU8, fxToBigUint64); mxAtomicsStore(); mxAtomicsTailBigUint64(); } |
167 | | |
168 | 0 | void fxInt8Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS1, fxToInteger); mxAtomicsSub(); mxAtomicsTail(); } |
169 | 0 | void fxInt16Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS2, fxToInteger); mxAtomicsSub(); mxAtomicsTail(); } |
170 | 0 | void fxInt32Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsSub(); mxAtomicsTail(); } |
171 | 0 | void fxInt64Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsSub(); mxAtomicsTailBigInt64(); } |
172 | 0 | void fxUint8Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU1, fxToUnsigned); mxAtomicsSub(); mxAtomicsTail(); } |
173 | 0 | void fxUint16Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU2, fxToUnsigned); mxAtomicsSub(); mxAtomicsTail(); } |
174 | 0 | void fxUint32Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU4, fxToUnsigned); mxAtomicsSub(); mxAtomicsTailOverflow(); } |
175 | 0 | void fxUint64Sub(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU8, fxToBigUint64); mxAtomicsSub(); mxAtomicsTailBigUint64(); } |
176 | | |
177 | 0 | void fxInt8Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS1, fxToInteger); mxAtomicsXor(); mxAtomicsTail(); } |
178 | 0 | void fxInt16Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS2, fxToInteger); mxAtomicsXor(); mxAtomicsTail(); } |
179 | 0 | void fxInt32Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsXor(); mxAtomicsTail(); } |
180 | 0 | void fxInt64Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsXor(); mxAtomicsTailBigInt64(); } |
181 | 0 | void fxUint8Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU1, fxToUnsigned); mxAtomicsXor(); mxAtomicsTail(); } |
182 | 0 | void fxUint16Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU2, fxToUnsigned); mxAtomicsXor(); mxAtomicsTail(); } |
183 | 0 | void fxUint32Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU4, fxToUnsigned); mxAtomicsXor(); mxAtomicsTailOverflow(); } |
184 | 0 | void fxUint64Xor(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, int endian) { mxAtomicsHead1(txU8, fxToBigUint64); mxAtomicsXor(); mxAtomicsTailBigUint64(); } |
185 | | |
186 | 0 | txInteger fxInt32Wait(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, txNumber timeout) { mxAtomicsHead1(txS4, fxToInteger); mxAtomicsLoad(); mxAtomicsTailWait(); } |
187 | 0 | txInteger fxInt64Wait(txMachine* the, txSlot* host, txInteger offset, txSlot* slot, txNumber timeout) { mxAtomicsHead1(txS8, fxToBigInt64); mxAtomicsLoad(); mxAtomicsTailWait(); } |
188 | | |
189 | | void fxBuildAtomics(txMachine* the) |
190 | 6.33k | { |
191 | 6.33k | txSlot* slot; |
192 | | |
193 | 6.33k | mxPush(mxObjectPrototype); |
194 | 6.33k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
195 | 6.33k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_get_byteLength), C_NULL, mxID(_byteLength), XS_DONT_ENUM_FLAG); |
196 | 6.33k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_get_growable), C_NULL, mxID(_growable), XS_DONT_ENUM_FLAG); |
197 | 6.33k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_get_maxByteLength), C_NULL, mxID(_maxByteLength), XS_DONT_ENUM_FLAG); |
198 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_grow), 1, mxID(_grow), XS_DONT_ENUM_FLAG); |
199 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_SharedArrayBuffer_prototype_slice), 2, mxID(_slice), XS_DONT_ENUM_FLAG); |
200 | 6.33k | slot = fxNextStringXProperty(the, slot, "SharedArrayBuffer", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
201 | 6.33k | mxSharedArrayBufferPrototype = *the->stack; |
202 | 6.33k | slot = fxBuildHostConstructor(the, mxCallback(fx_SharedArrayBuffer), 1, mxID(_SharedArrayBuffer)); |
203 | 6.33k | mxSharedArrayBufferConstructor = *the->stack; |
204 | 6.33k | slot = fxLastProperty(the, slot); |
205 | 6.33k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_species_get), C_NULL, mxID(_Symbol_species), XS_DONT_ENUM_FLAG); |
206 | 6.33k | mxPop(); |
207 | | |
208 | 6.33k | mxPush(mxObjectPrototype); |
209 | 6.33k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
210 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_add), 3, mxID(_add), XS_DONT_ENUM_FLAG); |
211 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_and), 3, mxID(_and), XS_DONT_ENUM_FLAG); |
212 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_compareExchange), 4, mxID(_compareExchange), XS_DONT_ENUM_FLAG); |
213 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_exchange), 3, mxID(_exchange), XS_DONT_ENUM_FLAG); |
214 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_isLockFree), 1, mxID(_isLockFree), XS_DONT_ENUM_FLAG); |
215 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_load), 2, mxID(_load), XS_DONT_ENUM_FLAG); |
216 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_or), 3, mxID(_or), XS_DONT_ENUM_FLAG); |
217 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_notify), 3, mxID(_notify), XS_DONT_ENUM_FLAG); |
218 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_store), 3, mxID(_store), XS_DONT_ENUM_FLAG); |
219 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_sub), 3, mxID(_sub), XS_DONT_ENUM_FLAG); |
220 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_wait), 4, mxID(_wait), XS_DONT_ENUM_FLAG); |
221 | 6.33k | #if mxECMAScript2024 |
222 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_waitAsync), 4, mxID(_waitAsync), XS_DONT_ENUM_FLAG); |
223 | 6.33k | #endif |
224 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_notify), 3, mxID(_wake), XS_DONT_ENUM_FLAG); |
225 | 6.33k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Atomics_xor), 3, mxID(_xor), XS_DONT_ENUM_FLAG); |
226 | 6.33k | slot = fxNextStringXProperty(the, slot, "Atomics", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
227 | 6.33k | mxPull(mxAtomicsObject); |
228 | 6.33k | } |
229 | | |
230 | | txSlot* fxCheckAtomicsArrayBuffer(txMachine* the, txSlot* slot, txBoolean onlyShared) |
231 | 0 | { |
232 | 0 | if ((!slot) || (!mxIsReference(slot))) |
233 | 0 | mxTypeError("typedArray.buffer: not an object"); |
234 | 0 | slot = slot->value.reference->next; |
235 | 0 | if (slot && (slot->kind == XS_HOST_KIND) && (slot->value.host.variant.destructor == fxReleaseSharedChunk)) |
236 | 0 | return slot; |
237 | 0 | if (onlyShared) |
238 | 0 | mxTypeError("typedArray.buffer: not a SharedArrayBuffer instance"); |
239 | 0 | if (slot && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_ARRAY_BUFFER_KIND)) { |
240 | 0 | if (slot->value.arrayBuffer.address == C_NULL) |
241 | 0 | mxTypeError("typedArray.buffer: detached"); |
242 | 0 | return slot; |
243 | 0 | } |
244 | 0 | mxTypeError("typedArray.buffer: not a SharedArrayBuffer instance, not an ArrayBuffer instance"); |
245 | 0 | return C_NULL; |
246 | 0 | } |
247 | | |
248 | | void* fxCheckAtomicsArrayBufferDetached(txMachine* the, txSlot* slot, txBoolean mutable) |
249 | 0 | { |
250 | 0 | if (slot->value.arrayBuffer.address == C_NULL) |
251 | 0 | mxTypeError("typedArray.buffer: detached"); |
252 | 0 | if (mutable && (slot->flag & XS_DONT_SET_FLAG)) |
253 | 0 | mxTypeError("typedArray.buffer: read-only"); |
254 | 0 | return slot->value.arrayBuffer.address; |
255 | 0 | } |
256 | | |
257 | | txInteger fxCheckAtomicsIndex(txMachine* the, txInteger i, txInteger length) |
258 | 0 | { |
259 | 0 | txSlot *slot = (mxArgc > i) ? mxArgv(i) : C_NULL; |
260 | 0 | if (slot && (XS_INTEGER_KIND == slot->kind)) { |
261 | 0 | int index = slot->value.integer; |
262 | 0 | if ((0 <= index) && (index < length)) |
263 | 0 | return index; |
264 | 0 | } |
265 | | |
266 | 0 | txNumber index = slot ? c_trunc(fxToNumber(the, slot)) : C_NAN; |
267 | 0 | if (c_isnan(index)) |
268 | 0 | index = 0; |
269 | 0 | if (index < 0) |
270 | 0 | mxRangeError("invalid index"); |
271 | 0 | else if (index >= length) |
272 | 0 | mxRangeError("invalid index"); |
273 | 0 | return (txInteger)index; |
274 | 0 | } |
275 | | |
276 | | txSlot* fxCheckAtomicsTypedArray(txMachine* the, txBoolean onlyInt32) |
277 | 0 | { |
278 | 0 | txSlot* slot = (mxArgc > 0) ? mxArgv(0) : C_NULL; |
279 | 0 | txID id; |
280 | 0 | if ((!slot) || (!mxIsReference(slot))) |
281 | 0 | mxTypeError("typedArray: not an object"); |
282 | 0 | slot = slot->value.reference->next; |
283 | 0 | if ((!slot) || ((slot->kind != XS_TYPED_ARRAY_KIND))) |
284 | 0 | mxTypeError("typedArray: not a TypedArray instance"); |
285 | 0 | id = slot->value.typedArray.dispatch->constructorID; |
286 | 0 | if (onlyInt32) { |
287 | 0 | if ((id != _Int32Array) && (id != _BigInt64Array)) |
288 | 0 | mxTypeError("typedArray: not an Int32Array instance"); |
289 | 0 | } |
290 | 0 | else { |
291 | 0 | if (id == _Float32Array) |
292 | 0 | mxTypeError("typedArray: Float32Array instance"); |
293 | 0 | else if (id == _Float64Array) |
294 | 0 | mxTypeError("typedArray: Float64Array instance"); |
295 | 0 | else if (id == _Uint8ClampedArray) |
296 | 0 | mxTypeError("typedArray: Uint8ClampedArray instance"); |
297 | 0 | #if mxFloat16 |
298 | 0 | else if (id == _Float16Array) |
299 | 0 | mxTypeError("typedArray: Float16Array instance"); |
300 | 0 | #endif |
301 | 0 | } |
302 | 0 | return slot; |
303 | 0 | } |
304 | | |
305 | | txSlot* fxCheckSharedArrayBuffer(txMachine* the, txSlot* slot, txString which) |
306 | 0 | { |
307 | 0 | if ((!slot) || (!mxIsReference(slot))) |
308 | 0 | mxTypeError("%s: not an object", which); |
309 | 0 | slot = slot->value.reference->next; |
310 | 0 | if ((!slot) || (slot->kind != XS_HOST_KIND) || (slot->value.host.variant.destructor != fxReleaseSharedChunk)) |
311 | 0 | mxTypeError("%s: not a SharedArrayBuffer instance", which); |
312 | 0 | return slot; |
313 | 0 | } |
314 | | |
315 | | void fxPushAtomicsValue(txMachine* the, int i, txID id) |
316 | 0 | { |
317 | 0 | txSlot* slot; |
318 | 0 | if (mxArgc > i) |
319 | 0 | mxPushSlot(mxArgv(i)); |
320 | 0 | else |
321 | 0 | mxPushUndefined(); |
322 | 0 | slot = the->stack; |
323 | 0 | if ((id == _BigInt64Array) || (id == _BigUint64Array)) |
324 | 0 | fxBigIntCoerce(the, slot); |
325 | 0 | else if (XS_INTEGER_KIND != slot->kind) { |
326 | 0 | txNumber value; |
327 | 0 | fxNumberCoerce(the, slot); |
328 | 0 | value = c_trunc(slot->value.number); |
329 | 0 | if (c_isnan(value) || (value == -0)) |
330 | 0 | value = 0; |
331 | 0 | slot->value.number = value; |
332 | 0 | } |
333 | 0 | } |
334 | | |
335 | | |
336 | | void fx_SharedArrayBuffer(txMachine* the) |
337 | 0 | { |
338 | 0 | txSlot* instance; |
339 | 0 | txS8 byteLength; |
340 | 0 | txS8 maxByteLength = -1; |
341 | 0 | txSlot* property; |
342 | 0 | if (mxIsUndefined(mxTarget)) |
343 | 0 | mxTypeError("call: SharedArrayBuffer"); |
344 | 0 | byteLength = fxArgToSafeByteLength(the, 0, 0); |
345 | 0 | if ((mxArgc > 1) && mxIsReference(mxArgv(1))) { |
346 | 0 | mxPushSlot(mxArgv(1)); |
347 | 0 | mxGetID(mxID(_maxByteLength)); |
348 | 0 | mxPullSlot(mxArgv(1)); |
349 | 0 | maxByteLength = fxArgToSafeByteLength(the, 1, -1); |
350 | 0 | } |
351 | 0 | if (maxByteLength >= 0) { |
352 | 0 | if (byteLength > maxByteLength) |
353 | 0 | mxRangeError("byteLength > maxByteLength"); |
354 | 0 | } |
355 | 0 | mxPushSlot(mxTarget); |
356 | 0 | fxGetPrototypeFromConstructor(the, &mxSharedArrayBufferPrototype); |
357 | 0 | instance = fxNewSlot(the); |
358 | 0 | instance->kind = XS_INSTANCE_KIND; |
359 | 0 | instance->value.instance.garbage = C_NULL; |
360 | 0 | instance->value.instance.prototype = the->stack->value.reference; |
361 | 0 | the->stack->value.reference = instance; |
362 | 0 | the->stack->kind = XS_REFERENCE_KIND; |
363 | 0 | if (byteLength > 0x7FFFFFFF) |
364 | 0 | mxRangeError("byteLength too big"); |
365 | 0 | if (maxByteLength > 0x7FFFFFFF) |
366 | 0 | mxRangeError("maxByteLength too big"); |
367 | 0 | property = instance->next = fxNewSlot(the); |
368 | 0 | property->flag = XS_INTERNAL_FLAG; |
369 | 0 | property->kind = XS_HOST_KIND; |
370 | 0 | property->value.host.data = fxCreateSharedChunk((txInteger)byteLength); |
371 | 0 | if (!property->value.host.data) { |
372 | 0 | property->value.host.variant.destructor = NULL; |
373 | 0 | mxRangeError("cannot allocate SharedArrayBuffer instance"); |
374 | 0 | } |
375 | 0 | property->value.host.variant.destructor = fxReleaseSharedChunk; |
376 | 0 | property = property->next = fxNewSlot(the); |
377 | 0 | property->flag = XS_INTERNAL_FLAG; |
378 | 0 | property->kind = XS_BUFFER_INFO_KIND; |
379 | 0 | property->value.bufferInfo.length = (txInteger)byteLength; |
380 | 0 | property->value.bufferInfo.maxLength = (txInteger)maxByteLength; |
381 | 0 | mxPullSlot(mxResult); |
382 | 0 | } |
383 | | |
384 | | void fx_SharedArrayBuffer_prototype_get_byteLength(txMachine* the) |
385 | 0 | { |
386 | 0 | txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this"); |
387 | 0 | txSlot* bufferInfo = host->next; |
388 | 0 | mxResult->kind = XS_INTEGER_KIND; |
389 | 0 | mxResult->value.integer = bufferInfo->value.bufferInfo.length; |
390 | 0 | } |
391 | | |
392 | | void fx_SharedArrayBuffer_prototype_get_growable(txMachine* the) |
393 | 0 | { |
394 | 0 | txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this"); |
395 | 0 | txSlot* bufferInfo = host->next; |
396 | 0 | mxResult->kind = XS_BOOLEAN_KIND; |
397 | 0 | mxResult->value.boolean = (bufferInfo->value.bufferInfo.maxLength >= 0) ? 1 : 0; |
398 | 0 | } |
399 | | |
400 | | void fx_SharedArrayBuffer_prototype_get_maxByteLength(txMachine* the) |
401 | 0 | { |
402 | 0 | txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this"); |
403 | 0 | txSlot* bufferInfo = host->next; |
404 | 0 | mxResult->kind = XS_INTEGER_KIND; |
405 | 0 | if (bufferInfo->value.bufferInfo.maxLength >= 0) |
406 | 0 | mxResult->value.integer = bufferInfo->value.bufferInfo.maxLength; |
407 | 0 | else |
408 | 0 | mxResult->value.integer = bufferInfo->value.bufferInfo.length; |
409 | 0 | } |
410 | | |
411 | | void fx_SharedArrayBuffer_prototype_grow(txMachine* the) |
412 | 0 | { |
413 | 0 | txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this"); |
414 | 0 | txSlot* bufferInfo = host->next; |
415 | 0 | txInteger maxByteLength, oldByteLength, newByteLength; |
416 | 0 | maxByteLength = bufferInfo->value.bufferInfo.maxLength; |
417 | 0 | if (maxByteLength < 0) |
418 | 0 | mxTypeError("this: not resizable"); |
419 | 0 | oldByteLength = bufferInfo->value.bufferInfo.length; |
420 | 0 | newByteLength = fxArgToByteLength(the, 0, 0); |
421 | 0 | if (newByteLength < oldByteLength) |
422 | 0 | mxRangeError("newLength < byteLength"); |
423 | 0 | if (newByteLength > maxByteLength) |
424 | 0 | mxRangeError("newLength > maxByteLength"); |
425 | 0 | mxRangeError("cannot grow SharedArrayBuffer instance"); |
426 | 0 | } |
427 | | |
428 | | void fx_SharedArrayBuffer_prototype_slice(txMachine* the) |
429 | 0 | { |
430 | 0 | txSlot* host = fxCheckSharedArrayBuffer(the, mxThis, "this"); |
431 | 0 | txSlot* bufferInfo = host->next; |
432 | 0 | txInteger length = bufferInfo->value.bufferInfo.length; |
433 | 0 | txInteger start = fxArgToIndexInteger(the, 0, 0, length); |
434 | 0 | txInteger stop = fxArgToIndexInteger(the, 1, length, length); |
435 | 0 | txSlot* result; |
436 | 0 | if (stop < start) |
437 | 0 | stop = start; |
438 | 0 | length = stop - start; |
439 | 0 | mxPushSlot(mxThis); |
440 | 0 | mxGetID(mxID(_constructor)); |
441 | 0 | fxToSpeciesConstructor(the, &mxSharedArrayBufferConstructor); |
442 | 0 | mxNew(); |
443 | 0 | mxPushInteger(length); |
444 | 0 | mxRunCount(1); |
445 | 0 | mxPullSlot(mxResult); |
446 | 0 | result = fxCheckSharedArrayBuffer(the, mxResult, "result"); |
447 | 0 | if (result == host) |
448 | 0 | mxTypeError("result: same SharedArrayBuffer instance"); |
449 | 0 | bufferInfo = result->next; |
450 | 0 | if (bufferInfo->value.bufferInfo.length < length) |
451 | 0 | mxTypeError("result: smaller SharedArrayBuffer instance"); |
452 | 0 | c_memcpy(result->value.host.data, ((txByte*)host->value.host.data + start), stop - start); |
453 | 0 | } |
454 | | |
455 | | void fx_Atomics_add(txMachine* the) |
456 | 0 | { |
457 | 0 | mxAtomicsDeclarations(0, 0); |
458 | 0 | fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID); |
459 | 0 | (*dispatch->value.typedArray.atomics->add)(the, host, offset, the->stack, 0); |
460 | 0 | mxPullSlot(mxResult); |
461 | 0 | } |
462 | | |
463 | | void fx_Atomics_and(txMachine* the) |
464 | 0 | { |
465 | 0 | mxAtomicsDeclarations(0, 0); |
466 | 0 | fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID); |
467 | 0 | (*dispatch->value.typedArray.atomics->and)(the, host, offset, the->stack, 0); |
468 | 0 | mxPullSlot(mxResult); |
469 | 0 | } |
470 | | |
471 | | void fx_Atomics_compareExchange(txMachine* the) |
472 | 0 | { |
473 | 0 | mxAtomicsDeclarations(0, 0); |
474 | 0 | fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID); |
475 | 0 | fxPushAtomicsValue(the, 3, dispatch->value.typedArray.dispatch->constructorID); |
476 | 0 | (*dispatch->value.typedArray.atomics->compareExchange)(the, host, offset, the->stack, 0); |
477 | 0 | mxPullSlot(mxResult); |
478 | 0 | mxPop(); |
479 | 0 | } |
480 | | |
481 | | void fx_Atomics_exchange(txMachine* the) |
482 | 0 | { |
483 | 0 | mxAtomicsDeclarations(0, 0); |
484 | 0 | fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID); |
485 | 0 | (*dispatch->value.typedArray.atomics->exchange)(the, host, offset, the->stack, 0); |
486 | 0 | mxPullSlot(mxResult); |
487 | 0 | } |
488 | | |
489 | | void fx_Atomics_isLockFree(txMachine* the) |
490 | 0 | { |
491 | 0 | txInteger size = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0; |
492 | 0 | mxResult->value.boolean = (size == 4) ? 1 : 0; |
493 | 0 | mxResult->kind = XS_BOOLEAN_KIND; |
494 | 0 | } |
495 | | |
496 | | void fx_Atomics_load(txMachine* the) |
497 | 0 | { |
498 | 0 | mxAtomicsDeclarations(0, 0); |
499 | 0 | (*dispatch->value.typedArray.atomics->load)(the, host, offset, mxResult, 0); |
500 | 0 | } |
501 | | |
502 | | void fx_Atomics_or(txMachine* the) |
503 | 0 | { |
504 | 0 | mxAtomicsDeclarations(0, 0); |
505 | 0 | fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID); |
506 | 0 | (*dispatch->value.typedArray.atomics->or)(the, host, offset, the->stack, 0); |
507 | 0 | mxPullSlot(mxResult); |
508 | 0 | } |
509 | | |
510 | | void fx_Atomics_notify(txMachine* the) |
511 | 0 | { |
512 | 0 | mxAtomicsDeclarations(1, 0); |
513 | 0 | txInteger count = ((mxArgc > 2) && !mxIsUndefined(mxArgv(2))) ? fxToInteger(the, mxArgv(2)) : 20; |
514 | 0 | if (count < 0) |
515 | 0 | count = 0; |
516 | 0 | if (host->kind == XS_ARRAY_BUFFER_KIND) { |
517 | 0 | mxResult->value.integer = 0; |
518 | 0 | } |
519 | 0 | else { |
520 | 0 | mxResult->value.integer = fxNotifySharedChunk(the, (txByte*)host->value.host.data + offset, count); |
521 | 0 | } |
522 | 0 | mxResult->kind = XS_INTEGER_KIND; |
523 | 0 | } |
524 | | |
525 | | void fx_Atomics_store(txMachine* the) |
526 | 0 | { |
527 | 0 | mxAtomicsDeclarations(0, 0); |
528 | 0 | fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID); |
529 | 0 | *mxResult = *the->stack; |
530 | 0 | (*dispatch->value.typedArray.atomics->store)(the, host, offset, the->stack, 0); |
531 | 0 | mxPop(); |
532 | 0 | } |
533 | | |
534 | | void fx_Atomics_sub(txMachine* the) |
535 | 0 | { |
536 | 0 | mxAtomicsDeclarations(0, 0); |
537 | 0 | fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID); |
538 | 0 | (*dispatch->value.typedArray.atomics->sub)(the, host, offset, the->stack, 0); |
539 | 0 | mxPullSlot(mxResult); |
540 | 0 | } |
541 | | |
542 | | void fx_Atomics_wait(txMachine* the) |
543 | 0 | { |
544 | 0 | mxAtomicsDeclarations(1, 1); |
545 | 0 | txNumber timeout; |
546 | 0 | txInteger result; |
547 | 0 | fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID); |
548 | 0 | timeout = (mxArgc > 3) ? fxToNumber(the, mxArgv(3)) : C_NAN; |
549 | 0 | if (c_isnan(timeout)) |
550 | 0 | timeout = C_INFINITY; |
551 | 0 | else if (timeout < 0) |
552 | 0 | timeout = 0; |
553 | 0 | result = (*dispatch->value.typedArray.atomics->wait)(the, host, offset, the->stack, timeout); |
554 | 0 | if (result < 0) |
555 | 0 | mxPushStringX("not-equal"); |
556 | 0 | else { |
557 | 0 | result = fxWaitSharedChunk(the, (txByte*)host->value.host.data + offset, timeout, C_NULL); |
558 | 0 | if (result == 0) |
559 | 0 | mxPushStringX("timed-out"); |
560 | 0 | else |
561 | 0 | mxPushStringX("ok"); |
562 | 0 | } |
563 | 0 | mxPullSlot(mxResult); |
564 | 0 | } |
565 | | |
566 | | #if mxECMAScript2024 |
567 | | void fx_Atomics_waitAsync(txMachine* the) |
568 | 0 | { |
569 | 0 | mxAtomicsDeclarations(1, 1); |
570 | 0 | txNumber timeout; |
571 | 0 | txInteger result; |
572 | 0 | txSlot* slot; |
573 | 0 | fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID); |
574 | 0 | timeout = (mxArgc > 3) ? fxToNumber(the, mxArgv(3)) : C_NAN; |
575 | 0 | if (c_isnan(timeout)) |
576 | 0 | timeout = C_INFINITY; |
577 | 0 | else if (timeout < 0) |
578 | 0 | timeout = 0; |
579 | 0 | result = (*dispatch->value.typedArray.atomics->wait)(the, host, offset, the->stack, timeout); |
580 | | |
581 | 0 | mxPush(mxObjectPrototype); |
582 | 0 | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
583 | 0 | slot = fxNextBooleanProperty(the, slot, (result <= 0) ? 0 : 1, mxID(_async), XS_NO_FLAG); |
584 | 0 | if (result < 0) |
585 | 0 | fxNextStringXProperty(the, slot, "not-equal", mxID(_value), XS_NO_FLAG); |
586 | 0 | else if (result == 0) |
587 | 0 | fxNextStringXProperty(the, slot, "timed-out", mxID(_value), XS_NO_FLAG); |
588 | 0 | else { |
589 | 0 | txSlot* resolveFunction; |
590 | 0 | txSlot* rejectFunction; |
591 | 0 | mxTemporary(resolveFunction); |
592 | 0 | mxTemporary(rejectFunction); |
593 | 0 | mxPush(mxPromiseConstructor); |
594 | 0 | fxNewPromiseCapability(the, resolveFunction, rejectFunction); |
595 | 0 | fxNextSlotProperty(the, slot, the->stack, mxID(_value), XS_NO_FLAG); |
596 | 0 | mxPop(); // promise |
597 | 0 | fxWaitSharedChunk(the, (txByte*)host->value.host.data + offset, timeout, resolveFunction); |
598 | 0 | mxPop(); // rejectFunction |
599 | 0 | mxPop(); // resolveFunction |
600 | 0 | } |
601 | 0 | mxPullSlot(mxResult); |
602 | 0 | } |
603 | | #endif |
604 | | |
605 | | void fx_Atomics_xor(txMachine* the) |
606 | 0 | { |
607 | 0 | mxAtomicsDeclarations(0, 0); |
608 | 0 | fxPushAtomicsValue(the, 2, dispatch->value.typedArray.dispatch->constructorID); |
609 | 0 | (*dispatch->value.typedArray.atomics->xor)(the, host, offset, the->stack, 0); |
610 | 0 | mxPullSlot(mxResult); |
611 | 0 | } |
612 | | |
613 | | #ifdef mxUseDefaultSharedChunks |
614 | | |
615 | | #if defined(mxUsePOSIXThreads) |
616 | | #define mxThreads 1 |
617 | | typedef pthread_cond_t txCondition; |
618 | | typedef pthread_mutex_t txMutex; |
619 | | typedef pthread_t txThread; |
620 | 0 | #define mxCreateCondition(CONDITION) pthread_cond_init(CONDITION,NULL) |
621 | 6.33k | #define mxCreateMutex(MUTEX) pthread_mutex_init(MUTEX,NULL) |
622 | 6.33k | #define mxCurrentThread() pthread_self() |
623 | 0 | #define mxDeleteCondition(CONDITION) pthread_cond_destroy(CONDITION) |
624 | 6.33k | #define mxDeleteMutex(MUTEX) pthread_mutex_destroy(MUTEX) |
625 | 6.33k | #define mxLockMutex(MUTEX) pthread_mutex_lock(MUTEX) |
626 | 6.33k | #define mxUnlockMutex(MUTEX) pthread_mutex_unlock(MUTEX) |
627 | 0 | #define mxWakeCondition(CONDITION) pthread_cond_signal(CONDITION) |
628 | | #elif defined(mxUseFreeRTOSTasks) |
629 | | #define mxThreads 1 |
630 | | |
631 | | #include "FreeRTOS.h" |
632 | | #if ESP32 |
633 | | #include "freertos/queue.h" |
634 | | #include "freertos/semphr.h" |
635 | | #else |
636 | | #include "queue.h" |
637 | | #include "semphr.h" |
638 | | #endif |
639 | | typedef TaskHandle_t txCondition; |
640 | | typedef struct { |
641 | | #if nrf52 |
642 | | SemaphoreHandle_t sem; |
643 | | #else |
644 | | QueueHandle_t handle; |
645 | | StaticSemaphore_t buffer; |
646 | | #endif |
647 | | } txMutex; |
648 | | typedef TaskHandle_t txThread; |
649 | | #define mxCreateCondition(CONDITION) *(CONDITION) = xTaskGetCurrentTaskHandle() |
650 | | #if nrf52 |
651 | | #define mxCreateMutex(MUTEX) (MUTEX)->sem = xSemaphoreCreateMutex() |
652 | | #else |
653 | | #define mxCreateMutex(MUTEX) (MUTEX)->handle = xSemaphoreCreateMutexStatic(&((MUTEX)->buffer)) |
654 | | #endif |
655 | | #define mxCurrentThread() xTaskGetCurrentTaskHandle() |
656 | | #define mxDeleteCondition(CONDITION) *(CONDITION) = NULL |
657 | | #if nrf52 |
658 | | #define mxDeleteMutex(MUTEX) vSemaphoreDelete((MUTEX)->sem) |
659 | | #define mxLockMutex(MUTEX) xSemaphoreTake((MUTEX)->sem, portMAX_DELAY) |
660 | | #define mxUnlockMutex(MUTEX) xSemaphoreGive((MUTEX)->sem) |
661 | | #else |
662 | | #define mxDeleteMutex(MUTEX) vSemaphoreDelete((MUTEX)->handle) |
663 | | #define mxLockMutex(MUTEX) xSemaphoreTake((MUTEX)->handle, portMAX_DELAY) |
664 | | #define mxUnlockMutex(MUTEX) xSemaphoreGive((MUTEX)->handle) |
665 | | #endif |
666 | | #define mxWakeCondition(CONDITION) xTaskNotifyGive(*(CONDITION)); |
667 | | #elif mxWindows |
668 | | #define mxThreads 1 |
669 | | typedef CONDITION_VARIABLE txCondition; |
670 | | typedef CRITICAL_SECTION txMutex; |
671 | | typedef DWORD txThread; |
672 | | #define mxCreateCondition(CONDITION) InitializeConditionVariable(CONDITION) |
673 | | #define mxCreateMutex(MUTEX) InitializeCriticalSection(MUTEX) |
674 | | #define mxCurrentThread() GetCurrentThreadId() |
675 | | #define mxDeleteCondition(CONDITION) (void)(CONDITION) |
676 | | #define mxDeleteMutex(MUTEX) DeleteCriticalSection(MUTEX) |
677 | | #define mxLockMutex(MUTEX) EnterCriticalSection(MUTEX) |
678 | | #define mxUnlockMutex(MUTEX) LeaveCriticalSection(MUTEX) |
679 | | #define mxWakeCondition(CONDITION) WakeConditionVariable(CONDITION) |
680 | | #else |
681 | | #define mxThreads 0 |
682 | | typedef void* txThread; |
683 | | #define mxCurrentThread() C_NULL |
684 | | #endif |
685 | | |
686 | | typedef struct sxSharedChunk txSharedChunk; |
687 | | typedef struct sxSharedCluster txSharedCluster; |
688 | | typedef struct sxSharedWaiter txSharedWaiter; |
689 | | |
690 | | typedef void (*txTimerCallback)(void* timer, void *refcon, txInteger refconSize); |
691 | | extern void fxRescheduleTimer(void* timer, txNumber timeout, txNumber interval); |
692 | | extern void* fxScheduleTimer(txNumber timeout, txNumber interval, txTimerCallback callback, void* refcon, txInteger refconSize); |
693 | | extern void fxUnscheduleTimer(void* timer); |
694 | | |
695 | | struct sxSharedChunk { |
696 | | #if mxThreads && !defined(mxUseGCCAtomics) |
697 | | txMutex mutex; |
698 | | #endif |
699 | | txSize size; |
700 | | txSize usage; |
701 | | }; |
702 | | |
703 | | struct sxSharedCluster { |
704 | | txThread mainThread; |
705 | | txSize usage; |
706 | | #if mxThreads |
707 | | txSharedWaiter* first; |
708 | | txMutex waiterMutex; |
709 | | #endif |
710 | | }; |
711 | | |
712 | | struct sxSharedWaiter { |
713 | | txSharedWaiter* next; |
714 | | txMachine* the; |
715 | | void* data; |
716 | | void* condition; |
717 | | void* timer; |
718 | | txSlot resolve; |
719 | | txBoolean ok; |
720 | | }; |
721 | | |
722 | | txSharedCluster* gxSharedCluster = C_NULL; |
723 | | |
724 | | void fxInitializeSharedCluster(txMachine* the) |
725 | 6.33k | { |
726 | 6.33k | if (gxSharedCluster) { |
727 | 0 | gxSharedCluster->usage++; |
728 | 0 | } |
729 | 6.33k | else { |
730 | 6.33k | gxSharedCluster = c_calloc(sizeof(txSharedCluster), 1); |
731 | 6.33k | if (gxSharedCluster) { |
732 | 6.33k | gxSharedCluster->mainThread = mxCurrentThread(); |
733 | 6.33k | gxSharedCluster->usage++; |
734 | 6.33k | #if mxThreads |
735 | 6.33k | mxCreateMutex(&gxSharedCluster->waiterMutex); |
736 | 6.33k | #endif |
737 | 6.33k | #ifdef mxInitializeSharedTimers |
738 | 6.33k | mxInitializeSharedTimers(); |
739 | 6.33k | #endif |
740 | 6.33k | } |
741 | 6.33k | } |
742 | 6.33k | } |
743 | | |
744 | | void fxTerminateSharedCluster(txMachine* the) |
745 | 6.33k | { |
746 | 6.33k | if (gxSharedCluster) { |
747 | 6.33k | #ifdef mxUnscheduleSharedTimer |
748 | 6.33k | if (the) { |
749 | 6.33k | txSharedWaiter** address; |
750 | 6.33k | txSharedWaiter* waiter; |
751 | 6.33k | mxLockMutex(&gxSharedCluster->waiterMutex); |
752 | 6.33k | address = &(gxSharedCluster->first); |
753 | 6.33k | while ((waiter = *address)) { |
754 | 0 | if (waiter->the == the) { |
755 | 0 | *address = waiter->next; |
756 | 0 | if (waiter->timer) |
757 | 0 | mxUnscheduleSharedTimer(waiter->timer); |
758 | 0 | c_free(waiter); |
759 | 0 | } |
760 | 0 | else |
761 | 0 | address = &(waiter->next); |
762 | 0 | } |
763 | 6.33k | mxUnlockMutex(&gxSharedCluster->waiterMutex); |
764 | 6.33k | } |
765 | 6.33k | #endif |
766 | 6.33k | gxSharedCluster->usage--; |
767 | 6.33k | if (gxSharedCluster->usage == 0) { |
768 | 6.33k | #ifdef mxTerminateSharedTimers |
769 | 6.33k | mxTerminateSharedTimers(); |
770 | 6.33k | #endif |
771 | 6.33k | #if mxThreads |
772 | 6.33k | mxDeleteMutex(&gxSharedCluster->waiterMutex); |
773 | 6.33k | #endif |
774 | 6.33k | c_free(gxSharedCluster); |
775 | 6.33k | gxSharedCluster = C_NULL; |
776 | 6.33k | } |
777 | 6.33k | } |
778 | 6.33k | } |
779 | | |
780 | | void* fxCreateSharedChunk(txInteger size) |
781 | 0 | { |
782 | 0 | txSharedChunk* chunk = c_malloc(sizeof(txSharedChunk) + size); |
783 | 0 | if (chunk) { |
784 | 0 | void* data = (((txByte*)chunk) + sizeof(txSharedChunk)); |
785 | | #if mxThreads && !defined(mxUseGCCAtomics) |
786 | | mxCreateMutex(&(chunk->mutex)); |
787 | | #endif |
788 | 0 | chunk->size = size; |
789 | 0 | chunk->usage = 1; |
790 | 0 | c_memset(data, 0, size); |
791 | 0 | return data; |
792 | 0 | } |
793 | 0 | return C_NULL; |
794 | 0 | } |
795 | | |
796 | | void fxLockSharedChunk(void* data) |
797 | 0 | { |
798 | | #if mxThreads && !defined(mxUseGCCAtomics) |
799 | | txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk)); |
800 | | mxLockMutex(&(chunk->mutex)); |
801 | | #endif |
802 | 0 | } |
803 | | |
804 | | txInteger fxMeasureSharedChunk(void* data) |
805 | 0 | { |
806 | 0 | txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk)); |
807 | 0 | return chunk->size; |
808 | 0 | } |
809 | | |
810 | | txInteger fxNotifySharedChunk(txMachine* the, void* data, txInteger count) |
811 | 0 | { |
812 | 0 | txInteger result = 0; |
813 | 0 | if (gxSharedCluster) { |
814 | 0 | #if mxThreads |
815 | 0 | txSharedWaiter* first = C_NULL; |
816 | 0 | txSharedWaiter* last = C_NULL; |
817 | 0 | txSharedWaiter** address; |
818 | 0 | txSharedWaiter* waiter; |
819 | 0 | mxLockMutex(&gxSharedCluster->waiterMutex); |
820 | 0 | address = &(gxSharedCluster->first); |
821 | 0 | while ((waiter = *address)) { |
822 | 0 | if (waiter->data == data) { |
823 | 0 | if (count == 0) |
824 | 0 | break; |
825 | 0 | count--; |
826 | 0 | if (first) |
827 | 0 | last->next = waiter; |
828 | 0 | else |
829 | 0 | first = waiter; |
830 | 0 | last = waiter; |
831 | 0 | *address = waiter->next; |
832 | 0 | waiter->next = C_NULL; |
833 | 0 | } |
834 | 0 | else |
835 | 0 | address = &(waiter->next); |
836 | 0 | } |
837 | 0 | waiter = first; |
838 | 0 | while (waiter) { |
839 | 0 | waiter->data = C_NULL; |
840 | 0 | if (waiter->condition) { |
841 | 0 | mxWakeCondition((txCondition*)waiter->condition); |
842 | 0 | } |
843 | 0 | else { |
844 | 0 | waiter->ok = 1; |
845 | 0 | #ifdef mxRescheduleSharedTimer |
846 | 0 | mxRescheduleSharedTimer(waiter->timer, 0, 0); |
847 | | #else |
848 | | fxAbort(the, XS_DEAD_STRIP_EXIT); |
849 | | #endif |
850 | 0 | } |
851 | 0 | result++; |
852 | 0 | waiter = waiter->next; |
853 | 0 | } |
854 | 0 | mxUnlockMutex(&gxSharedCluster->waiterMutex); |
855 | 0 | #endif |
856 | 0 | } |
857 | 0 | return result; |
858 | 0 | } |
859 | | |
860 | | void* fxRetainSharedChunk(void* data) |
861 | 0 | { |
862 | 0 | txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk)); |
863 | 0 | txS4 result = 0; |
864 | 0 | txS4 value = 1; |
865 | 0 | txS4* address = &(chunk->usage); |
866 | | #ifndef mxUseGCCAtomics |
867 | | txBoolean lock = 1; |
868 | | #endif |
869 | 0 | mxAtomicsAdd(); |
870 | 0 | if (result == 0) |
871 | 0 | return C_NULL; |
872 | 0 | return data; |
873 | 0 | } |
874 | | |
875 | | void fxReleaseSharedChunk(void* data) |
876 | 0 | { |
877 | 0 | txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk)); |
878 | 0 | txS4 result = 0; |
879 | 0 | txS4 value = 1; |
880 | 0 | txS4* address = &(chunk->usage); |
881 | | #ifndef mxUseGCCAtomics |
882 | | txBoolean lock = 1; |
883 | | #endif |
884 | 0 | mxAtomicsSub(); |
885 | 0 | if (result == 1) { |
886 | 0 | c_free(chunk); |
887 | 0 | } |
888 | 0 | } |
889 | | |
890 | | void fxUnlockSharedChunk(void* data) |
891 | 0 | { |
892 | | #if mxThreads && !defined(mxUseGCCAtomics) |
893 | | txSharedChunk* chunk = (txSharedChunk*)(((txByte*)data) - sizeof(txSharedChunk)); |
894 | | mxUnlockMutex(&(chunk->mutex)); |
895 | | #endif |
896 | 0 | } |
897 | | |
898 | | #if mxThreads |
899 | | void fxWaitSharedChunkCallback(void* timer, void* refcon, txInteger refconSize) |
900 | 0 | { |
901 | 0 | txSharedWaiter** address = (txSharedWaiter**)refcon; |
902 | 0 | txSharedWaiter* waiter = *address; |
903 | 0 | txSharedWaiter* link; |
904 | 0 | txMachine* the; |
905 | 0 | mxLockMutex(&gxSharedCluster->waiterMutex); |
906 | 0 | address = &(gxSharedCluster->first); |
907 | 0 | while ((link = *address)) { |
908 | 0 | if (link == waiter) |
909 | 0 | *address = link->next; |
910 | 0 | else |
911 | 0 | address = &(link->next); |
912 | 0 | } |
913 | 0 | mxUnlockMutex(&gxSharedCluster->waiterMutex); |
914 | 0 | the = waiter->the; |
915 | 0 | fxBeginHost(waiter->the); |
916 | 0 | mxTry(the) { |
917 | 0 | mxPushUndefined(); |
918 | 0 | mxPush(waiter->resolve); |
919 | 0 | mxCall(); |
920 | 0 | if (waiter->ok) |
921 | 0 | mxPushStringX("ok"); |
922 | 0 | else |
923 | 0 | mxPushStringX("timed-out"); |
924 | 0 | mxRunCount(1); |
925 | 0 | mxPop(); |
926 | 0 | } |
927 | 0 | mxCatch(the) { |
928 | 0 | } |
929 | 0 | fxForget(the, &waiter->resolve); |
930 | 0 | fxEndHost(the); |
931 | 0 | c_free(waiter); |
932 | 0 | } |
933 | | #endif |
934 | | |
935 | | txInteger fxWaitSharedChunk(txMachine* the, void* data, txNumber timeout, txSlot* resolveFunction) |
936 | 0 | { |
937 | 0 | txInteger result = 1; |
938 | 0 | if (gxSharedCluster) { |
939 | 0 | #if mxThreads |
940 | 0 | txSharedWaiter* waiter; |
941 | 0 | txSharedWaiter** address; |
942 | 0 | txSharedWaiter* link; |
943 | 0 | waiter = c_calloc(1, sizeof(txSharedWaiter)); |
944 | 0 | if (!waiter) |
945 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
946 | 0 | waiter->the = the; |
947 | 0 | waiter->data = data; |
948 | 0 | mxLockMutex(&gxSharedCluster->waiterMutex); |
949 | 0 | address = &(gxSharedCluster->first); |
950 | 0 | while ((link = *address)) |
951 | 0 | address = &(link->next); |
952 | 0 | *address = waiter; |
953 | | |
954 | 0 | if (resolveFunction) { |
955 | 0 | mxUnlockMutex(&gxSharedCluster->waiterMutex); |
956 | 0 | waiter->resolve = *resolveFunction; |
957 | 0 | fxRemember(the, &waiter->resolve); |
958 | 0 | #ifdef mxScheduleSharedTimer |
959 | 0 | waiter->timer = mxScheduleSharedTimer(timeout, 0, (txSharedTimerCallback)fxWaitSharedChunkCallback, &waiter, sizeof(txSharedWaiter*)); |
960 | 0 | if (!waiter->timer) |
961 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
962 | | #else |
963 | | fxAbort(the, XS_DEAD_STRIP_EXIT); |
964 | | #endif |
965 | 0 | } |
966 | 0 | else if (gxSharedCluster->mainThread != mxCurrentThread()) { |
967 | 0 | txCondition condition; |
968 | 0 | mxCreateCondition(&condition); |
969 | 0 | waiter->condition = &condition; |
970 | 0 | if (timeout == C_INFINITY) { |
971 | 0 | #if defined(mxUsePOSIXThreads) |
972 | 0 | while (waiter->data == data) |
973 | 0 | pthread_cond_wait(&condition, &gxSharedCluster->waiterMutex); |
974 | | #elif defined(mxUseFreeRTOSTasks) |
975 | | mxUnlockMutex(&gxSharedCluster->waiterMutex); |
976 | | ulTaskNotifyTake(pdTRUE, portMAX_DELAY); |
977 | | mxLockMutex(&gxSharedCluster->waiterMutex); |
978 | | #else |
979 | | while (waiter->data == data) |
980 | | SleepConditionVariableCS(&condition, &gxSharedCluster->waiterMutex, INFINITE); |
981 | | #endif |
982 | 0 | } |
983 | 0 | else { |
984 | 0 | #if defined(mxUsePOSIXThreads) |
985 | 0 | struct timespec ts; |
986 | 0 | timeout += fxDateNow(); |
987 | 0 | ts.tv_sec = c_floor(timeout / 1000); |
988 | 0 | ts.tv_nsec = c_fmod(timeout, 1000) * 1000000; |
989 | 0 | while (waiter->data == data) { |
990 | 0 | result = (pthread_cond_timedwait(&condition, &gxSharedCluster->waiterMutex, &ts) == ETIMEDOUT) ? 0 : 1; |
991 | 0 | if (!result) |
992 | 0 | break; |
993 | 0 | } |
994 | | #elif defined(mxUseFreeRTOSTasks) |
995 | | mxUnlockMutex(&gxSharedCluster->waiterMutex); |
996 | | ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(timeout)); |
997 | | mxLockMutex(&gxSharedCluster->waiterMutex); |
998 | | result = (waiter->data == data) ? 0 : 1; |
999 | | #else |
1000 | | timeout += fxDateNow(); |
1001 | | while (waiter->data == data) { |
1002 | | result = (SleepConditionVariableCS(&condition, &gxSharedCluster->waiterMutex, (DWORD)(timeout - fxDateNow()))) ? 1 : 0; |
1003 | | if (!result) |
1004 | | break; |
1005 | | } |
1006 | | #endif |
1007 | 0 | } |
1008 | 0 | address = &(gxSharedCluster->first); |
1009 | 0 | while ((link = *address)) { |
1010 | 0 | if (link == waiter) |
1011 | 0 | *address = link->next; |
1012 | 0 | else |
1013 | 0 | address = &(link->next); |
1014 | 0 | } |
1015 | 0 | mxUnlockMutex(&gxSharedCluster->waiterMutex); |
1016 | 0 | c_free(waiter); |
1017 | 0 | mxDeleteCondition(&condition); |
1018 | 0 | } |
1019 | 0 | else { |
1020 | 0 | mxTypeError("main thread cannot wait"); |
1021 | 0 | } |
1022 | 0 | #endif |
1023 | 0 | } |
1024 | 0 | else { |
1025 | 0 | mxTypeError("no shared cluster"); |
1026 | 0 | } |
1027 | 0 | return result; |
1028 | 0 | } |
1029 | | |
1030 | | #endif /* mxUseDefaultSharedChunks */ |
1031 | | |
1032 | | |