1
1
#include < chrono>
2
+ #include < condition_variable>
3
+ #include < mutex>
2
4
#include < thread>
3
5
#include " napi.h"
4
6
@@ -17,6 +19,9 @@ static struct ThreadSafeFunctionInfo {
17
19
bool startSecondary;
18
20
FunctionReference jsFinalizeCallback;
19
21
uint32_t maxQueueSize;
22
+ bool closeCalledFromJs;
23
+ std::mutex protect;
24
+ std::condition_variable signal;
20
25
} tsfnInfo;
21
26
22
27
static void TSFNCallJS (Env env,
@@ -42,7 +47,7 @@ static int ints[ARRAY_LENGTH];
42
47
43
48
static void SecondaryThread () {
44
49
if (tsfn.Release () != napi_ok) {
45
- Error::Fatal (" SecondaryThread " , " ThreadSafeFunction.Release() failed" );
50
+ Error::Fatal (" TypedSecondaryThread " , " ThreadSafeFunction.Release() failed" );
46
51
}
47
52
}
48
53
@@ -52,7 +57,8 @@ static void DataSourceThread() {
52
57
53
58
if (info->startSecondary ) {
54
59
if (tsfn.Acquire () != napi_ok) {
55
- Error::Fatal (" DataSourceThread" , " ThreadSafeFunction.Acquire() failed" );
60
+ Error::Fatal (" TypedDataSourceThread" ,
61
+ " ThreadSafeFunction.Acquire() failed" );
56
62
}
57
63
58
64
threads[1 ] = std::thread (SecondaryThread);
@@ -75,13 +81,13 @@ static void DataSourceThread() {
75
81
break ;
76
82
}
77
83
78
- if (info->maxQueueSize == 0 ) {
79
- // Let's make this thread really busy for 200 ms to give the main thread a
80
- // chance to abort .
81
- auto start = std::chrono::high_resolution_clock::now ( );
82
- constexpr auto MS_200 = std::chrono::milliseconds ( 200 );
83
- for (; std::chrono::high_resolution_clock::now () - start < MS_200;)
84
- ;
84
+ if (info->abort && info-> type != ThreadSafeFunctionInfo::NON_BLOCKING ) {
85
+ // Let's make this thread really busy to give the main thread a chance to
86
+ // abort / close .
87
+ std::unique_lock<std::mutex> lk (info-> protect );
88
+ while (!info-> closeCalledFromJs ) {
89
+ info-> signal . wait (lk);
90
+ }
85
91
}
86
92
87
93
switch (status) {
@@ -98,20 +104,22 @@ static void DataSourceThread() {
98
104
break ;
99
105
100
106
default :
101
- Error::Fatal (" DataSourceThread" , " ThreadSafeFunction.*Call() failed" );
107
+ Error::Fatal (" TypedDataSourceThread" ,
108
+ " ThreadSafeFunction.*Call() failed" );
102
109
}
103
110
}
104
111
105
112
if (info->type == ThreadSafeFunctionInfo::NON_BLOCKING && !queueWasFull) {
106
- Error::Fatal (" DataSourceThread " , " Queue was never full" );
113
+ Error::Fatal (" TypedDataSourceThread " , " Queue was never full" );
107
114
}
108
115
109
116
if (info->abort && !queueWasClosing) {
110
- Error::Fatal (" DataSourceThread " , " Queue was never closing" );
117
+ Error::Fatal (" TypedDataSourceThread " , " Queue was never closing" );
111
118
}
112
119
113
120
if (!queueWasClosing && tsfn.Release () != napi_ok) {
114
- Error::Fatal (" DataSourceThread" , " ThreadSafeFunction.Release() failed" );
121
+ Error::Fatal (" TypedDataSourceThread" ,
122
+ " ThreadSafeFunction.Release() failed" );
115
123
}
116
124
}
117
125
@@ -123,6 +131,11 @@ static Value StopThread(const CallbackInfo& info) {
123
131
} else {
124
132
tsfn.Release ();
125
133
}
134
+ {
135
+ std::lock_guard<std::mutex> _ (tsfnInfo.protect );
136
+ tsfnInfo.closeCalledFromJs = true ;
137
+ tsfnInfo.signal .notify_one ();
138
+ }
126
139
return Value ();
127
140
}
128
141
@@ -145,6 +158,7 @@ static Value StartThreadInternal(const CallbackInfo& info,
145
158
tsfnInfo.abort = info[1 ].As <Boolean >();
146
159
tsfnInfo.startSecondary = info[2 ].As <Boolean >();
147
160
tsfnInfo.maxQueueSize = info[3 ].As <Number>().Uint32Value ();
161
+ tsfnInfo.closeCalledFromJs = false ;
148
162
149
163
tsfn = TSFN::New (info.Env (),
150
164
info[0 ].As <Function>(),
@@ -163,7 +177,7 @@ static Value StartThreadInternal(const CallbackInfo& info,
163
177
164
178
static Value Release (const CallbackInfo& /* info */ ) {
165
179
if (tsfn.Release () != napi_ok) {
166
- Error::Fatal (" Release" , " ThreadSafeFunction .Release() failed" );
180
+ Error::Fatal (" Release" , " TypedThreadSafeFunction .Release() failed" );
167
181
}
168
182
return Value ();
169
183
}
0 commit comments