Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/pthread/library_pthread.c
6171 views
1
/*
2
* Copyright 2015 The Emscripten Authors. All rights reserved.
3
* Emscripten is available under two separate licenses, the MIT license and the
4
* University of Illinois/NCSA Open Source License. Both these licenses can be
5
* found in the LICENSE file.
6
*/
7
8
#define _GNU_SOURCE
9
#include "../internal/libc.h"
10
#include "../internal/pthread_impl.h"
11
#include <assert.h>
12
#include <dirent.h>
13
#include <errno.h>
14
#include <fcntl.h>
15
#include <poll.h>
16
#include <pthread.h>
17
#include <stdarg.h>
18
#include <stdlib.h>
19
#include <sys/ioctl.h>
20
#include <sys/mman.h>
21
#include <sys/socket.h>
22
#include <sys/stat.h>
23
#include <sys/statvfs.h>
24
#include <sys/time.h>
25
#include <termios.h>
26
#include <threads.h>
27
#include <unistd.h>
28
#include <utime.h>
29
30
#include <emscripten.h>
31
#include <emscripten/proxying.h>
32
#include <emscripten/stack.h>
33
#include <emscripten/threading.h>
34
35
#include "threading_internal.h"
36
#include "emscripten_internal.h"
37
38
int emscripten_pthread_attr_gettransferredcanvases(const pthread_attr_t* a, const char** str) {
39
*str = a->_a_transferredcanvases;
40
return 0;
41
}
42
43
int emscripten_pthread_attr_settransferredcanvases(pthread_attr_t* a, const char* str) {
44
a->_a_transferredcanvases = str;
45
return 0;
46
}
47
48
int sched_get_priority_max(int policy) {
49
// Web workers do not actually support prioritizing threads,
50
// but mimic values that Linux apparently reports, see
51
// http://man7.org/linux/man-pages/man2/sched_get_priority_min.2.html
52
if (policy == SCHED_FIFO || policy == SCHED_RR)
53
return 99;
54
else
55
return 0;
56
}
57
58
int sched_get_priority_min(int policy) {
59
// Web workers do not actually support prioritizing threads,
60
// but mimic values that Linux apparently reports, see
61
// http://man7.org/linux/man-pages/man2/sched_get_priority_min.2.html
62
if (policy == SCHED_FIFO || policy == SCHED_RR)
63
return 1;
64
else
65
return 0;
66
}
67
68
int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *restrict attr, int *restrict prioceiling)
69
{
70
// Not supported either in Emscripten or musl, return a faked value.
71
if (prioceiling) *prioceiling = 99;
72
return 0;
73
}
74
75
int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling)
76
{
77
// Not supported either in Emscripten or musl, return an error.
78
return EPERM;
79
}
80
81
static uint32_t dummyZeroAddress = 0;
82
83
void emscripten_thread_sleep(double msecs) {
84
double now = emscripten_get_now();
85
double target = now + msecs;
86
87
// If we have less than this many msecs left to wait, busy spin that instead.
88
double min_ms_slice_to_sleep = 0.1;
89
90
// runtime thread may need to run proxied calls, so sleep in very small slices to be responsive.
91
double max_ms_slice_to_sleep = emscripten_is_main_runtime_thread() ? 1 : 100;
92
93
emscripten_conditional_set_current_thread_status(
94
EM_THREAD_STATUS_RUNNING, EM_THREAD_STATUS_SLEEPING);
95
96
do {
97
// Keep processing the main loop of the calling thread.
98
__pthread_testcancel(); // pthreads spec: sleep is a cancellation point, so must test if this
99
// thread is cancelled during the sleep.
100
emscripten_current_thread_process_queued_calls();
101
102
now = emscripten_get_now();
103
double ms_to_sleep = target - now;
104
if (ms_to_sleep < min_ms_slice_to_sleep)
105
continue;
106
if (ms_to_sleep > max_ms_slice_to_sleep)
107
ms_to_sleep = max_ms_slice_to_sleep;
108
emscripten_futex_wait(&dummyZeroAddress, 0, ms_to_sleep);
109
now = emscripten_get_now();
110
} while (now < target);
111
112
emscripten_conditional_set_current_thread_status(
113
EM_THREAD_STATUS_SLEEPING, EM_THREAD_STATUS_RUNNING);
114
}
115
116
static struct pthread __main_pthread;
117
118
pthread_t emscripten_main_runtime_thread_id() {
119
return &__main_pthread;
120
}
121
122
void emscripten_current_thread_process_queued_calls() {
123
emscripten_proxy_execute_queue(emscripten_proxy_get_system_queue());
124
}
125
126
void emscripten_main_thread_process_queued_calls() {
127
assert(emscripten_is_main_runtime_thread());
128
emscripten_current_thread_process_queued_calls();
129
}
130
131
int _emscripten_thread_is_valid(pthread_t thread) {
132
return thread->self == thread;
133
}
134
135
static void *dummy_tsd[1] = { 0 };
136
weak_alias(dummy_tsd, __pthread_tsd_main);
137
138
// See system/lib/README.md for static constructor ordering.
139
__attribute__((constructor(48)))
140
void _emscripten_init_main_thread(void) {
141
// The pthread struct has a field that points to itself - this is used as
142
// a magic ID to detect whether the pthread_t structure is 'alive'.
143
__main_pthread.self = &__main_pthread;
144
__main_pthread.detach_state = DT_JOINABLE;
145
// pthread struct robust_list head should point to itself.
146
__main_pthread.robust_list.head = &__main_pthread.robust_list.head;
147
// Main thread ID is always 1. It can't be 0 because musl assumes
148
// tid is always non-zero.
149
__main_pthread.tid = getpid();
150
__main_pthread.locale = &libc.global_locale;
151
// pthread struct prev and next should initially point to itself (see __init_tp),
152
// this is used by pthread_key_delete for deleting thread-specific data.
153
__main_pthread.next = __main_pthread.prev = &__main_pthread;
154
__main_pthread.tsd = (void **)__pthread_tsd_main;
155
156
_emscripten_init_main_thread_js(&__main_pthread);
157
158
__main_pthread.stack = (void*)emscripten_stack_get_base();
159
__main_pthread.stack_size = emscripten_stack_get_base() - emscripten_stack_get_end();
160
161
_emscripten_thread_mailbox_init(&__main_pthread);
162
_emscripten_thread_mailbox_await(&__main_pthread);
163
}
164
165