forked from R3Conclave/conclave-core-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpthread_changes.diff
656 lines (600 loc) · 26 KB
/
pthread_changes.diff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
diff --git a/common/inc/internal/se_error_internal.h b/common/inc/internal/se_error_internal.h
index ac19e47..91f63ed 100644
--- a/common/inc/internal/se_error_internal.h
+++ b/common/inc/internal/se_error_internal.h
@@ -84,7 +84,7 @@ typedef enum _se_status_internal_t
/*error code for untrusted event of SE mutex*/
SE_ERROR_MUTEX_GET_EVENT = SE_INTERNAL_ERROR(0x3001),
SE_ERROR_MUTEX_WAIT_EVENT = SE_INTERNAL_ERROR(0x3002),
- SE_ERROR_MUTEX_WAKE_EVENT = SE_INTERNAL_ERROR(0x3003),
+ SE_ERROR_MUTEX_WAKE_EVENT = SE_INTERNAL_ERROR(0x3003)
} se_status_internal_t;
#endif
diff --git a/common/inc/internal/se_event.h b/common/inc/internal/se_event.h
index e2a1501..100e087 100644
--- a/common/inc/internal/se_event.h
+++ b/common/inc/internal/se_event.h
@@ -44,6 +44,11 @@ typedef void * se_handle_t;
#define SE_MUTEX_INVALID 0x1
#define SE_MUTEX_ERROR_WAKE 0x2
#define SE_MUTEX_ERROR_WAIT 0x3
+#define SE_MUTEX_TIMEDOUT 0x4
+
+// R3: Flag that can be or'd with the timeout parameter for se_event_wait_timeout()
+// that specifies the timeout should be in nS and not S
+#define TIMEOUT_NS (1ull << 63)
#ifdef __cplusplus
extern "C" {
diff --git a/common/inc/internal/se_lock.hpp b/common/inc/internal/se_lock.hpp
index 4852779..02459de 100644
--- a/common/inc/internal/se_lock.hpp
+++ b/common/inc/internal/se_lock.hpp
@@ -56,7 +56,7 @@ public:
~Cond(){se_mutex_destroy(&m_mutex); se_thread_cond_destroy(&m_cond);}
void lock(){se_mutex_lock(&m_mutex);}
void unlock(){se_mutex_unlock(&m_mutex);}
- void wait(){se_thread_cond_wait(&m_cond, &m_mutex);}
+ bool wait(uint64_t timeout_seconds = 0){return se_thread_cond_timedwait(&m_cond, &m_mutex, timeout_seconds) ? true : false;}
void signal(){se_thread_cond_signal(&m_cond);}
void broadcast(){se_thread_cond_broadcast(&m_cond);}
private:
@@ -67,10 +67,15 @@ private:
class LockGuard: private Uncopyable
{
public:
- LockGuard(Mutex* mutex):m_mutex(mutex){m_mutex->lock();}
- ~LockGuard(){m_mutex->unlock();}
+ LockGuard(Mutex* mutex):m_mutex(mutex), m_cond(NULL) {m_mutex->lock();}
+ LockGuard(Cond* cond):m_mutex(NULL), m_cond(cond) {m_cond->lock();}
+ ~LockGuard(){
+ if (m_mutex) m_mutex->unlock();
+ if (m_cond) m_cond->unlock();
+ }
private:
Mutex* m_mutex;
+ Cond* m_cond;
};
#endif
diff --git a/common/inc/internal/se_thread.h b/common/inc/internal/se_thread.h
index df39e1c..d44af1b 100644
--- a/common/inc/internal/se_thread.h
+++ b/common/inc/internal/se_thread.h
@@ -40,6 +40,7 @@
#endif
#include <string.h>
#include <unistd.h>
+#include <stdint.h>
#include <sys/syscall.h>
#include <pthread.h>
typedef pthread_mutex_t se_mutex_t;
@@ -60,6 +61,7 @@ int se_mutex_unlock(se_mutex_t* mutex);
int se_mutex_destroy(se_mutex_t* mutex);
void se_thread_cond_init(se_cond_t* cond);
+int se_thread_cond_timedwait(se_cond_t *cond, se_mutex_t *mutex, uint64_t timeout);
int se_thread_cond_wait(se_cond_t *cond, se_mutex_t *mutex);
int se_thread_cond_signal(se_cond_t *cond);
int se_thread_cond_broadcast(se_cond_t *cond);
diff --git a/common/inc/sgx_error.h b/common/inc/sgx_error.h
index 67b0983..fab8d73 100644
--- a/common/inc/sgx_error.h
+++ b/common/inc/sgx_error.h
@@ -121,6 +121,9 @@ typedef enum _status_t
SGX_ERROR_INVALID_ATT_KEY_CERT_DATA = SGX_MK_ERROR(0x8004), /* TThe data returned by the platform library's sgx_get_quote_config() is invalid.*/
SGX_ERROR_PLATFORM_CERT_UNAVAILABLE = SGX_MK_ERROR(0x8005), /* The PCK Cert for the platform is not available.*/
+ // R3: Condition wait timeout
+ SGX_WAIT_TIMEOUT = SGX_MK_ERROR(0xa001), /* A wait operation timed out */
+
SGX_INTERNAL_ERROR_ENCLAVE_CREATE_INTERRUPTED = SGX_MK_ERROR(0xF001), /* The ioctl for enclave_create unexpectedly failed with EINTR. */
} sgx_status_t;
diff --git a/common/inc/sgx_thread.h b/common/inc/sgx_thread.h
index 323a79c..568b78f 100644
--- a/common/inc/sgx_thread.h
+++ b/common/inc/sgx_thread.h
@@ -133,6 +133,7 @@ int SGXAPI sgx_thread_cond_init(sgx_thread_cond_t *cond, const sgx_thread_condat
int SGXAPI sgx_thread_cond_destroy(sgx_thread_cond_t *cond);
int SGXAPI sgx_thread_cond_wait(sgx_thread_cond_t *cond, sgx_thread_mutex_t *mutex);
+int SGXAPI sgx_thread_cond_timedwait(sgx_thread_cond_t *cond, sgx_thread_mutex_t *mutex, uint64_t timeout);
int SGXAPI sgx_thread_cond_signal(sgx_thread_cond_t *cond);
int SGXAPI sgx_thread_cond_broadcast(sgx_thread_cond_t *cond);
diff --git a/common/inc/sgx_tstdc.edl b/common/inc/sgx_tstdc.edl
index 6dc006b..f965d64 100644
--- a/common/inc/sgx_tstdc.edl
+++ b/common/inc/sgx_tstdc.edl
@@ -34,7 +34,7 @@ enclave {
[cdecl] void sgx_oc_cpuidex([out] int cpuinfo[4], int leaf, int subleaf);
/* Go outside and wait on my untrusted event */
- [cdecl] int sgx_thread_wait_untrusted_event_ocall([user_check] const void *self);
+ [cdecl] int sgx_thread_wait_untrusted_event_ocall([user_check] const void *self, size_t timeout);
/* Wake a thread waiting on its untrusted event */
[cdecl] int sgx_thread_set_untrusted_event_ocall([user_check] const void *waiter);
diff --git a/common/inc/tlibc/pthread.h b/common/inc/tlibc/pthread.h
index ab3b605..8d0f49b 100644
--- a/common/inc/tlibc/pthread.h
+++ b/common/inc/tlibc/pthread.h
@@ -95,6 +95,12 @@ int SGXAPI pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *);
int SGXAPI pthread_cond_destroy(pthread_cond_t *);
int SGXAPI pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
+// R3: The posix version of this function always uses an absolute time as the timeout. We do not
+// have the concept of current time in the enclave so this version uses a relative time. Because
+// it deviates from standard pthreads it has been given a leading underscore. If you have access to
+// a time source then you can implement the standard pthread_cond_timedwait by calculating the relative
+// time then calling this function.
+int SGXAPI _pthread_cond_timedwait(pthread_cond_t *, pthread_mutex_t *, const struct timespec*);
int SGXAPI pthread_cond_signal(pthread_cond_t *);
int SGXAPI pthread_cond_broadcast(pthread_cond_t *);
diff --git a/common/src/se_event.c b/common/src/se_event.c
index b47e283..05df86b 100644
--- a/common/src/se_event.c
+++ b/common/src/se_event.c
@@ -62,24 +62,36 @@ int se_event_wait(se_handle_t se_event)
*/
int se_event_wait_timeout(se_handle_t se_event, uint64_t timeout)
{
+ int retval = SE_MUTEX_SUCCESS;
if (se_event == NULL)
return SE_MUTEX_INVALID;
- if(0 == timeout)
+ if(0 == (timeout & ~TIMEOUT_NS))
return se_event_wait(se_event);
if (__sync_fetch_and_add((int*)se_event, -1) == 0)
{
struct timespec time;
- time.tv_sec = (time_t)timeout;
- time.tv_nsec = 0;
+ // Timeouts are specified in seconds or nanoseconds. This is determined
+ // by the presence of the TIMEOUT_NS flag.
+ if (timeout & TIMEOUT_NS) {
+ uint64_t nanoseconds = timeout & ~TIMEOUT_NS;
+ time.tv_sec = (time_t)(nanoseconds / 1000000000);
+ time.tv_nsec = (long)(nanoseconds % 1000000000);
+ }
+ else {
+ time.tv_sec = (time_t)timeout;
+ time.tv_nsec = 0;
+ }
syscall(__NR_futex, se_event, FUTEX_WAIT, -1, &time, NULL, 0);
//If the futex is exit with timeout (se_event still equal to ' -1'), the se_event value need reset to 0.
//Or the event wait will unworkable in next round checking "if (__sync_fetch_and_add((int*)se_event, -1) == 0)".
- __sync_val_compare_and_swap((int*)se_event, -1, 0);
+ if (__sync_val_compare_and_swap((int*)se_event, -1, 0) == -1) {
+ retval = SE_MUTEX_TIMEDOUT;
+ }
}
- return SE_MUTEX_SUCCESS;
+ return retval;
}
diff --git a/common/src/se_thread.c b/common/src/se_thread.c
index 5af4c45..8db884e 100644
--- a/common/src/se_thread.c
+++ b/common/src/se_thread.c
@@ -55,6 +55,17 @@ void se_thread_cond_init(se_cond_t* cond)
memcpy(cond, &tmp, sizeof(tmp));
}
+int se_thread_cond_timedwait(se_cond_t *cond, se_mutex_t *mutex, uint64_t timeout) {
+ struct timespec tm;
+ if ((timeout == 0) || (clock_gettime(CLOCK_REALTIME, &tm) != 0)) {
+ return (0 == pthread_cond_wait(cond, mutex));
+ }
+ else {
+ tm.tv_sec += (time_t)timeout;
+ return (0 == pthread_cond_timedwait(cond, mutex, &tm));
+ }
+}
+
int se_thread_cond_wait(se_cond_t *cond, se_mutex_t *mutex){return (0 == pthread_cond_wait(cond, mutex));}
int se_thread_cond_signal(se_cond_t *cond){return (0 == pthread_cond_signal(cond));}
int se_thread_cond_broadcast(se_cond_t *cond){return (0 == pthread_cond_broadcast(cond));}
diff --git a/psw/urts/enclave_mutex.cpp b/psw/urts/enclave_mutex.cpp
index bda7345..c7467a8 100644
--- a/psw/urts/enclave_mutex.cpp
+++ b/psw/urts/enclave_mutex.cpp
@@ -37,7 +37,8 @@
#include "se_error_internal.h"
/* wait on untrusted event */
-extern "C" int sgx_thread_wait_untrusted_event_ocall(const void *self)
+/* R3: Takes a timeout in nanoseconds as a parameter. Specify 0 for infinite wait. */
+extern "C" int sgx_thread_wait_untrusted_event_ocall(const void *self, size_t timeout)
{
if (self == NULL)
return SGX_ERROR_INVALID_PARAMETER;
@@ -46,7 +47,10 @@ extern "C" int sgx_thread_wait_untrusted_event_ocall(const void *self)
if (hevent == NULL)
return SE_ERROR_MUTEX_GET_EVENT;
- if (SE_MUTEX_SUCCESS != se_event_wait(hevent))
+ int retval = se_event_wait_timeout(hevent, (uint64_t)timeout | TIMEOUT_NS);
+ if (retval == SE_MUTEX_TIMEDOUT)
+ return SGX_WAIT_TIMEOUT;
+ if (SE_MUTEX_SUCCESS != retval)
return SE_ERROR_MUTEX_WAIT_EVENT;
return SGX_SUCCESS;
@@ -91,5 +95,5 @@ extern "C" int sgx_thread_setwait_untrusted_events_ocall(const void *waiter, con
int ret = sgx_thread_set_untrusted_event_ocall(waiter);
if (ret != SGX_SUCCESS) return ret;
- return sgx_thread_wait_untrusted_event_ocall(self);
+ return sgx_thread_wait_untrusted_event_ocall(self, 0);
}
diff --git a/psw/urts/enclave_thread.cpp b/psw/urts/enclave_thread.cpp
index 9ed1e0c..1432c49 100644
--- a/psw/urts/enclave_thread.cpp
+++ b/psw/urts/enclave_thread.cpp
@@ -115,7 +115,8 @@ extern "C" sgx_status_t pthread_wait_timeout_ocall(unsigned long long waiter, un
if (hevent == NULL)
return SGX_ERROR_DEVICE_BUSY;
- if (SE_MUTEX_SUCCESS != se_event_wait_timeout(hevent, timeout))
+ int retval = se_event_wait_timeout(hevent, timeout);
+ if ((SE_MUTEX_SUCCESS != retval) && (SE_MUTEX_TIMEDOUT != retval))
return SGX_ERROR_UNEXPECTED;
return SGX_SUCCESS;
@@ -130,3 +131,9 @@ extern "C" sgx_status_t pthread_wakeup_ocall(unsigned long long waiter)
return SGX_SUCCESS;
}
+extern "C" void sgx_configure_thread_blocking(sgx_enclave_id_t enclave_id, uint64_t deadlock_timeout) {
+ CEnclave *enclave = CEnclavePool::instance()->get_enclave(enclave_id);
+ if (enclave) {
+ enclave->get_thread_pool()->enable_thread_blocking(deadlock_timeout);
+ }
+}
\ No newline at end of file
diff --git a/psw/urts/linux/urts.lds b/psw/urts/linux/urts.lds
index 44897f2..776e0fd 100644
--- a/psw/urts/linux/urts.lds
+++ b/psw/urts/linux/urts.lds
@@ -12,6 +12,7 @@
pthread_create_ocall;
pthread_wait_timeout_ocall;
pthread_wakeup_ocall;
+ sgx_configure_thread_blocking;
sgx_oc_cpuidex;
sgx_get_target_info;
sgx_create_encrypted_enclave;
diff --git a/psw/urts/tcs.cpp b/psw/urts/tcs.cpp
index df3feeb..f2d2fdb 100644
--- a/psw/urts/tcs.cpp
+++ b/psw/urts/tcs.cpp
@@ -41,6 +41,7 @@
#include "rts.h"
#include "enclave.h"
#include "get_thread_id.h"
+#include <iostream>
int do_ecall(const int fn, const void *ocall_table, const void *ms, CTrustThread *trust_thread);
@@ -64,6 +65,14 @@ CTrustThread::~CTrustThread()
m_event = NULL;
}
+void CTrustThread::decrease_ref() {
+ if (--m_reference == 0) {
+ if (m_enclave) {
+ m_enclave->get_thread_pool()->notify_free_thread();
+ }
+ }
+}
+
se_handle_t CTrustThread::get_event()
{
if(m_event == NULL)
@@ -96,6 +105,8 @@ CTrustThreadPool::CTrustThreadPool(uint32_t tcs_min_pool)
m_utility_thread = NULL;
m_tcs_min_pool = tcs_min_pool;
m_need_to_wait_for_new_thread = false;
+ m_thread_blocking = false;
+ m_deadlock_timeout = 0;
}
CTrustThreadPool::~CTrustThreadPool()
@@ -231,7 +242,7 @@ CTrustThread * CTrustThreadPool::add_thread(tcs_t * const tcs, CEnclave * const
{
m_unallocated_threads.push_back(trust_thread);
}
-
+ notify_free_thread();
return trust_thread;
}
@@ -294,6 +305,7 @@ void CTrustThreadPool::reset()
}
m_thread_list = NULL;
+ notify_free_thread();
return;
}
@@ -330,21 +342,31 @@ CTrustThread * CTrustThreadPool::_acquire_free_thread()
CTrustThread * CTrustThreadPool::acquire_free_thread()
{
LockGuard lock(&m_thread_mutex);
- CTrustThread *trust_thread = _acquire_free_thread();
- // for edmm feature, we don't support simulation mode yet
- // m_utility_thread will be NULL in simulation mode
- if(NULL == trust_thread && NULL != m_utility_thread)
- {
- m_need_to_wait_for_new_thread_cond.lock();
- m_utility_thread->get_enclave()->fill_tcs_mini_pool_fn();
- m_need_to_wait_for_new_thread = true;
- while(m_need_to_wait_for_new_thread != false)
+ CTrustThread* trust_thread = NULL;
+ while (1) {
+ trust_thread = _acquire_free_thread();
+ // for edmm feature, we don't support simulation mode yet
+ // m_utility_thread will be NULL in simulation mode
+ if(NULL == trust_thread && NULL != m_utility_thread)
{
- m_need_to_wait_for_new_thread_cond.wait();
+ m_need_to_wait_for_new_thread_cond.lock();
+ m_utility_thread->get_enclave()->fill_tcs_mini_pool_fn();
+ m_need_to_wait_for_new_thread = true;
+ while(m_need_to_wait_for_new_thread != false)
+ {
+ m_need_to_wait_for_new_thread_cond.wait();
+ }
+ m_need_to_wait_for_new_thread_cond.unlock();
+ trust_thread = _acquire_free_thread();
+ }
+ if (trust_thread) {
+ break;
+ }
+ if (!m_thread_blocking || !m_thread_mutex.wait(m_deadlock_timeout)) {
+ break;
}
- m_need_to_wait_for_new_thread_cond.unlock();
- trust_thread = _acquire_free_thread();
}
+
if(trust_thread)
{
trust_thread->reset_ref();
@@ -410,20 +429,28 @@
}
else
{
- trust_thread = _acquire_thread();
- // for edmm feature, we don't support simulation mode yet
- // m_utility_thread will be NULL in simulation mode
- if(NULL == trust_thread && NULL != m_utility_thread)
- {
- m_need_to_wait_for_new_thread_cond.lock();
- m_utility_thread->get_enclave()->fill_tcs_mini_pool_fn();
- m_need_to_wait_for_new_thread = true;
- while(m_need_to_wait_for_new_thread != false)
+ while (1) {
+ trust_thread = _acquire_thread();
+ // for edmm feature, we don't support simulation mode yet
+ // m_utility_thread will be NULL in simulation mode
+ if(NULL == trust_thread && NULL != m_utility_thread)
{
- m_need_to_wait_for_new_thread_cond.wait();
+ m_need_to_wait_for_new_thread_cond.lock();
+ m_utility_thread->get_enclave()->fill_tcs_mini_pool_fn();
+ m_need_to_wait_for_new_thread = true;
+ while(m_need_to_wait_for_new_thread != false)
+ {
+ m_need_to_wait_for_new_thread_cond.wait();
+ }
+ m_need_to_wait_for_new_thread_cond.unlock();
+ trust_thread = _acquire_thread();
+ }
+ if (trust_thread) {
+ break;
+ }
+ if (!m_thread_blocking || !m_thread_mutex.wait(m_deadlock_timeout)) {
+ break;
}
- m_need_to_wait_for_new_thread_cond.unlock();
- trust_thread = _acquire_thread();
}
}
@@ -567,6 +592,15 @@ sgx_status_t CTrustThreadPool::fill_tcs_mini_pool()
return ret;
}
+void CTrustThreadPool::notify_free_thread() {
+ // This can safely be called with the mutex locked or unlocked.
+ m_thread_mutex.broadcast();
+}
+
+void CTrustThreadPool::enable_thread_blocking(uint64_t deadlock_timeout) {
+ m_thread_blocking = true;
+ m_deadlock_timeout = deadlock_timeout;
+}
//The return value stand for the number of free trust thread.
int CThreadPoolBindMode::garbage_collect()
diff --git a/psw/urts/tcs.h b/psw/urts/tcs.h
index 389915a..102e666 100644
--- a/psw/urts/tcs.h
+++ b/psw/urts/tcs.h
@@ -52,7 +52,7 @@ public:
~CTrustThread();
int get_reference() { return m_reference; }
void increase_ref() { m_reference++; }
- void decrease_ref() { m_reference--; }
+ void decrease_ref();
tcs_t *get_tcs() { return m_tcs; }
CEnclave *get_enclave() { return m_enclave; }
se_handle_t get_event();
@@ -86,6 +86,8 @@ public:
bool is_dynamic_thread_exist();
int bind_pthread(const se_thread_id_t thread_id, CTrustThread * const trust_thread);
void add_to_free_thread_vector(CTrustThread* it);
+ void notify_free_thread();
+ void enable_thread_blocking(uint64_t deadlock_timeout);
protected:
virtual int garbage_collect() = 0;
inline int find_thread(std::vector<se_thread_id_t> &thread_vector, se_thread_id_t thread_id);
@@ -97,7 +99,7 @@ protected:
std::vector<CTrustThread *> m_free_thread_vector;
std::vector<CTrustThread *> m_unallocated_threads;
Node<se_thread_id_t, CTrustThread *> *m_thread_list;
- Mutex m_thread_mutex; //protect thread_cache list. The mutex is recursive.
+ Cond m_thread_mutex; //protect thread_cache list. The mutex is recursive.
//Thread can operate the list when it get the mutex
Mutex m_free_thread_mutex; //protect free threads.
Cond m_need_to_wait_for_new_thread_cond;
@@ -107,6 +109,8 @@ private:
CTrustThread *m_utility_thread;
uint64_t m_tcs_min_pool;
bool m_need_to_wait_for_new_thread;
+ uint64_t m_deadlock_timeout;
+ bool m_thread_blocking;
};
class CThreadPoolBindMode : public CTrustThreadPool
diff --git a/sdk/pthread/pthread.cpp b/sdk/pthread/pthread.cpp
index 28dff18..4862026 100644
--- a/sdk/pthread/pthread.cpp
+++ b/sdk/pthread/pthread.cpp
@@ -86,6 +86,7 @@ static volatile sgx_pthread_common_queue_t g_work_queue = {NULL, NULL};
static volatile sgx_spinlock_t g_work_queue_lock = SGX_SPINLOCK_INITIALIZER;
/* This TLS variable is used to store every thread's unique Identity */
__thread pthread_info pthread_info_tls = {NULL, NULL, {0, 0, 0, 0, 0, 0, 0, 0}, SGX_SUCCESS};
+__thread pthread external_thread;
bool _pthread_enabled(void)
{
@@ -93,6 +94,15 @@ bool _pthread_enabled(void)
pthread_info_tls.m_pthread = NULL;
pthread_info_tls.m_state = SGX_SUCCESS;
memset((char*)&pthread_info_tls.m_mark, 0x00, sizeof(jmp_buf));
+
+ // R3: This function is called for threads created inside the enclave during the next ecall
+ // but also for host threads during the first ecall from that thread. Use this to setup a
+ // placeholder m_pthread so that pthread_self() returns a unique thread ID even for host
+ // threads.
+ memset(&external_thread, 0, sizeof(external_thread));
+ external_thread.state = _STATE_EXTERNAL;
+ pthread_info_tls.m_pthread = &external_thread;
+
return true;
}
@@ -115,7 +125,7 @@ sgx_status_t _pthread_tls_get_state(void)
void _pthread_wakeup_join(void* ms)
{
pthread_t thread = pthread_info_tls.m_pthread;
- if(NULL == thread)
+ if((NULL == thread) || (thread->state == _STATE_EXTERNAL))
//do nothing
return;
diff --git a/sdk/pthread/pthread_cond.cpp b/sdk/pthread/pthread_cond.cpp
index 38b47be..e5f1ef7 100644
--- a/sdk/pthread/pthread_cond.cpp
+++ b/sdk/pthread/pthread_cond.cpp
@@ -23,9 +23,17 @@
#include "sgx_trts.h"
#include "sgx_spinlock.h"
#include "pthread_imp.h"
+#include "se_error_internal.h"
#include "util.h"
+#include <time.h>
+
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+
int pthread_cond_init(pthread_cond_t *condp, const pthread_condattr_t *attr)
{
UNUSED(attr);
@@ -42,6 +42,20 @@ int pthread_cond_wait(pthread_cond_t *condp, pthread_mutex_t *mutexp)
return sgx_thread_cond_wait(condp, mutexp);
}
+int _pthread_cond_timedwait(pthread_cond_t *condp, pthread_mutex_t *mutexp, const struct timespec* reltime)
+{
+ if (!reltime) {
+ return pthread_cond_wait(condp, mutexp);
+ }
+ // R3: The posix version of this function always uses an absolute time as the timeout. We do not
+ // have the concept of current time in the SGX SDK so this version uses a relative time. Because
+ // it deviates from standard pthreads it has been given a leading underscore. If you have access to
+ // a time source then you can implement the standard pthread_cond_timedwait by calculating the relative
+ // time then calling this function.
+ uint64_t timeout = (reltime->tv_sec * 1000000000 + reltime->tv_nsec);
+ return (sgx_thread_cond_timedwait(condp, mutexp, timeout) == (int)SGX_WAIT_TIMEOUT) ? ETIMEDOUT : 0;
+}
+
int pthread_cond_signal(pthread_cond_t *condp)
{
return sgx_thread_cond_signal(condp);
diff --git a/sdk/pthread/pthread_imp.h b/sdk/pthread/pthread_imp.h
index 161a04e..a291da9 100644
--- a/sdk/pthread/pthread_imp.h
+++ b/sdk/pthread/pthread_imp.h
@@ -71,6 +71,7 @@ typedef enum {
_STATE_WAKEDUP,
_STATE_ERROR_OUT_OF_TCS,
_STATE_ERROR_UNEXPECTED,
+ _STATE_EXTERNAL // R3: Signals a host thread and not a thread created using pthread_create().
} _pthread_state;
typedef struct _pthread
diff --git a/sdk/tlibthread/sethread_cond.cpp b/sdk/tlibthread/sethread_cond.cpp
index 0dea08d..57d1799 100644
--- a/sdk/tlibthread/sethread_cond.cpp
+++ b/sdk/tlibthread/sethread_cond.cpp
@@ -64,7 +64,7 @@ int sgx_thread_cond_destroy(sgx_thread_cond_t *cond)
return 0;
}
-int sgx_thread_cond_wait(sgx_thread_cond_t *cond, sgx_thread_mutex_t *mutex)
+int sgx_thread_cond_timedwait(sgx_thread_cond_t *cond, sgx_thread_mutex_t *mutex, uint64_t timeout)
{
CHECK_PARAMETER(cond);
CHECK_PARAMETER(mutex);
@@ -87,7 +87,7 @@ int sgx_thread_cond_wait(sgx_thread_cond_t *cond, sgx_thread_mutex_t *mutex)
SPIN_UNLOCK(&cond->m_lock);
/* OPT: if there is a thread waiting on the mutex, wake it in a single OCALL. */
if (waiter == SGX_THREAD_T_NULL) {
- sgx_thread_wait_untrusted_event_ocall(&ret, TD2TCS(self));
+ sgx_thread_wait_untrusted_event_ocall(&ret, TD2TCS(self), timeout);
} else {
sgx_thread_setwait_untrusted_events_ocall(&ret, TD2TCS(waiter), TD2TCS(self));
waiter = SGX_THREAD_T_NULL;
@@ -98,12 +98,24 @@ int sgx_thread_cond_wait(sgx_thread_cond_t *cond, sgx_thread_mutex_t *mutex)
if (tmp == self) break; /* stop searching and re-wait outside */
}
if (tmp == SGX_THREAD_T_NULL) break; /* current thread isn't in the queue */
+
+ if (ret != 0) {
+ // Some sort of error, which may be a timeout. As this thread is not waiting
+ // anymore we need to remove it from the queue.
+ QUEUE_REMOVE(&cond->m_queue, self);
+ break;
+ }
}
SPIN_UNLOCK(&cond->m_lock);
sgx_thread_mutex_lock(mutex);
- return 0;
+ return ret;
+}
+
+int sgx_thread_cond_wait(sgx_thread_cond_t *cond, sgx_thread_mutex_t *mutex)
+{
+ return sgx_thread_cond_timedwait(cond, mutex, 0);
}
int sgx_thread_cond_signal(sgx_thread_cond_t *cond)
diff --git a/sdk/tlibthread/sethread_internal.h b/sdk/tlibthread/sethread_internal.h
index d875ac2..1b1fdce 100644
--- a/sdk/tlibthread/sethread_internal.h
+++ b/sdk/tlibthread/sethread_internal.h
@@ -119,7 +119,7 @@ typedef struct _thread_data_t *pTD;
} while (0)
/* Generated OCALLs */
-extern "C" sgx_status_t sgx_thread_wait_untrusted_event_ocall(int* retval, const void *self);
+extern "C" sgx_status_t sgx_thread_wait_untrusted_event_ocall(int* retval, const void *self, uint64_t timeout);
extern "C" sgx_status_t sgx_thread_set_untrusted_event_ocall(int* retval, const void *waiter);
extern "C" sgx_status_t sgx_thread_set_multiple_untrusted_events_ocall(int* retval, const void** waiters, size_t total);
extern "C" sgx_status_t sgx_thread_setwait_untrusted_events_ocall(int* retval, const void *waiter, const void *self);
diff --git a/sdk/tlibthread/sethread_mutex.cpp b/sdk/tlibthread/sethread_mutex.cpp
index 38cef7c..82a53b3 100644
--- a/sdk/tlibthread/sethread_mutex.cpp
+++ b/sdk/tlibthread/sethread_mutex.cpp
@@ -117,7 +117,7 @@ int sgx_thread_mutex_lock(sgx_thread_mutex_t *mutex)
SPIN_UNLOCK(&mutex->m_lock);
int err = 0;
- sgx_thread_wait_untrusted_event_ocall(&err, TD2TCS(self));
+ sgx_thread_wait_untrusted_event_ocall(&err, TD2TCS(self), 0);
}
/* NOTREACHED */
diff --git a/sdk/tlibthread/sethread_rwlock.cpp b/sdk/tlibthread/sethread_rwlock.cpp
index fc440e2..2899979 100644
--- a/sdk/tlibthread/sethread_rwlock.cpp
+++ b/sdk/tlibthread/sethread_rwlock.cpp
@@ -121,7 +121,7 @@ int sgx_thread_rwlock_rdlock(sgx_thread_rwlock_t *rwlock)
SPIN_UNLOCK(&rwlock->m_lock);
//make an OCall to wait for the lock
- sgx_thread_wait_untrusted_event_ocall(&err, TD2TCS(self));
+ sgx_thread_wait_untrusted_event_ocall(&err, TD2TCS(self), 0);
SPIN_LOCK(&rwlock->m_lock);
@@ -212,7 +212,7 @@ int sgx_thread_rwlock_wrlock(sgx_thread_rwlock_t *rwlock)
SPIN_UNLOCK(&rwlock->m_lock);
//make an OCall to wait for the lock
- sgx_thread_wait_untrusted_event_ocall(&err, TD2TCS(self));
+ sgx_thread_wait_untrusted_event_ocall(&err, TD2TCS(self), 0);
SPIN_LOCK(&rwlock->m_lock);