| 105 | #define ROUND_UP(x, ALIGNMENT) (((x)+ALIGNMENT-1)&-ALIGNMENT) |
| 106 | |
| 107 | int __pthread_create(pthread_t* restrict res, |
| 108 | const pthread_attr_t* restrict attrp, |
| 109 | void* (*entry)(void*), |
| 110 | void* restrict arg) { |
| 111 | // Note on LSAN: lsan intercepts/wraps calls to pthread_create so any |
| 112 | // allocations we do here should not be considered leaks. |
| 113 | // See: lsan_interceptors.cpp. |
| 114 | if (!res) { |
| 115 | return EINVAL; |
| 116 | } |
| 117 | |
| 118 | if (!libc.threaded) { |
| 119 | for (FILE *f=*__ofl_lock(); f; f=f->next) |
| 120 | init_file_lock(f); |
| 121 | __ofl_unlock(); |
| 122 | init_file_lock(__stdin_used); |
| 123 | init_file_lock(__stdout_used); |
| 124 | init_file_lock(__stderr_used); |
| 125 | libc.threaded = 1; |
| 126 | } |
| 127 | |
| 128 | pthread_attr_t attr = { 0 }; |
| 129 | if (attrp && attrp != __ATTRP_C11_THREAD) attr = *attrp; |
| 130 | if (!attr._a_stacksize) { |
| 131 | attr._a_stacksize = __default_stacksize; |
| 132 | } |
| 133 | |
| 134 | // Allocate memory for new thread. The layout of the thread block is |
| 135 | // as follows. From low to high address: |
| 136 | // |
| 137 | // 1. pthread struct (sizeof struct pthread) |
| 138 | // 2. tls data (__builtin_wasm_tls_size()) |
| 139 | // 3. tsd pointers (__pthread_tsd_size) |
| 140 | // 4. stack (__default_stacksize AKA -sDEFAULT_PTHREAD_STACK_SIZE) |
| 141 | size_t size = sizeof(struct pthread); |
| 142 | if (__builtin_wasm_tls_size()) { |
| 143 | size += __builtin_wasm_tls_size() + __builtin_wasm_tls_align() - 1; |
| 144 | } |
| 145 | size += __pthread_tsd_size + TSD_ALIGN - 1; |
| 146 | size_t zero_size = size; |
| 147 | if (!attr._a_stackaddr) { |
| 148 | size += attr._a_stacksize + STACK_ALIGN - 1; |
| 149 | } |
| 150 | |
| 151 | // Allocate all the data for the new thread and zero-initialize all parts |
| 152 | // except for the stack. |
| 153 | unsigned char* block = emscripten_builtin_malloc(size); |
| 154 | memset(block, 0, zero_size); |
| 155 | |
| 156 | uintptr_t offset = (uintptr_t)block; |
| 157 | |
| 158 | // 1. pthread struct |
| 159 | struct pthread *new = (struct pthread*)offset; |
| 160 | offset += sizeof(struct pthread); |
| 161 | |
| 162 | new->map_base = block; |
| 163 | new->map_size = size; |
| 164 |
nothing calls this directly
no test coverage detected