forked from python/cpython
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pythongh-95174: Add pthread stubs for WASI
Neither WASI nor default builds with Emscripten have support for threading. While Emscripten comes with pthread stubs, WASI-SDK 16 and earlier are lacking stubs. Python initially used WASIX stubs to provide pthread stubs. This changeset introduces stubs modelled after Emscripten's stubs. Emscripten without pthread emulation now has ``sys.thread_info.name`` ``pthread-stubs``, too.
- Loading branch information
Showing
14 changed files
with
327 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#ifndef Py_CPYTHON_PTRHEAD_STUBS_H | ||
#define Py_CPYTHON_PTRHEAD_STUBS_H | ||
|
||
#if !defined(HAVE_PTHREAD_STUBS) | ||
# error "this header file requires stubbed pthreads." | ||
#endif | ||
|
||
#ifndef _POSIX_THREADS | ||
# define _POSIX_THREADS 1 | ||
#endif | ||
|
||
/* Minimal pthread stubs for CPython | ||
* | ||
* The stubs implement a bare minimum pthread API for CPython. | ||
* - pthread_create() fails. | ||
* - pthread_exit() calls exit(0). | ||
* - pthread_key_*() functions implement minimal TSS without destructor. | ||
* - all other functions do nothing and return 0. | ||
*/ | ||
|
||
#ifdef __wasi__ | ||
// WASI's bits/alltypes.h provides type definitions when __NEED_ is set. | ||
// The header file can be included multiple times. | ||
# define __NEED_pthread_cond_t 1 | ||
# define __NEED_pthread_condattr_t 1 | ||
# define __NEED_pthread_mutex_t 1 | ||
# define __NEED_pthread_mutexattr_t 1 | ||
# define __NEED_pthread_key_t 1 | ||
# define __NEED_pthread_t 1 | ||
# define __NEED_pthread_attr_t 1 | ||
# include <bits/alltypes.h> | ||
#else | ||
typedef struct { void *__x; } pthread_cond_t; | ||
typedef struct { unsigned __attr; } pthread_condattr_t; | ||
typedef struct { void *__x; } pthread_mutex_t; | ||
typedef struct { unsigned __attr; } pthread_mutexattr_t; | ||
typedef unsigned pthread_key_t; | ||
typedef unsigned pthread_t; | ||
typedef struct { unsigned __attr; } pthread_attr_t; | ||
#endif | ||
|
||
// mutex | ||
PyAPI_FUNC(int) pthread_mutex_init(pthread_mutex_t *restrict mutex, | ||
const pthread_mutexattr_t *restrict attr); | ||
PyAPI_FUNC(int) pthread_mutex_destroy(pthread_mutex_t *mutex); | ||
PyAPI_FUNC(int) pthread_mutex_trylock(pthread_mutex_t *mutex); | ||
PyAPI_FUNC(int) pthread_mutex_lock(pthread_mutex_t *mutex); | ||
PyAPI_FUNC(int) pthread_mutex_unlock(pthread_mutex_t *mutex); | ||
|
||
// condition | ||
PyAPI_FUNC(int) pthread_cond_init(pthread_cond_t *restrict cond, | ||
const pthread_condattr_t *restrict attr); | ||
PyAPI_FUNC(int) pthread_cond_destroy(pthread_cond_t *cond); | ||
PyAPI_FUNC(int) pthread_cond_wait(pthread_cond_t *restrict cond, | ||
pthread_mutex_t *restrict mutex); | ||
PyAPI_FUNC(int) pthread_cond_timedwait(pthread_cond_t *restrict cond, | ||
pthread_mutex_t *restrict mutex, | ||
const struct timespec *restrict abstime); | ||
PyAPI_FUNC(int) pthread_cond_signal(pthread_cond_t *cond); | ||
PyAPI_FUNC(int) pthread_condattr_init(pthread_condattr_t *attr); | ||
PyAPI_FUNC(int) pthread_condattr_setclock( | ||
pthread_condattr_t *attr, clockid_t clock_id); | ||
|
||
// pthread | ||
PyAPI_FUNC(int) pthread_create(pthread_t *restrict thread, | ||
const pthread_attr_t *restrict attr, | ||
void *(*start_routine)(void *), | ||
void *restrict arg); | ||
PyAPI_FUNC(int) pthread_detach(pthread_t thread); | ||
PyAPI_FUNC(pthread_t) pthread_self(void); | ||
PyAPI_FUNC(int) pthread_exit(void *retval) __attribute__ ((__noreturn__)); | ||
PyAPI_FUNC(int) pthread_attr_init(pthread_attr_t *attr); | ||
PyAPI_FUNC(int) pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); | ||
PyAPI_FUNC(int) pthread_attr_destroy(pthread_attr_t *attr); | ||
|
||
|
||
// pthread_key | ||
#ifndef PTHREAD_KEYS_MAX | ||
# define PTHREAD_KEYS_MAX 128 | ||
#endif | ||
|
||
PyAPI_FUNC(int) pthread_key_create(pthread_key_t *key, | ||
void (*destr_function)(void *)); | ||
PyAPI_FUNC(int) pthread_key_delete(pthread_key_t key); | ||
PyAPI_FUNC(void *) pthread_getspecific(pthread_key_t key); | ||
PyAPI_FUNC(int) pthread_setspecific(pthread_key_t key, const void *value); | ||
|
||
#endif // Py_CPYTHON_PTRHEAD_STUBS_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 2 additions & 0 deletions
2
Misc/NEWS.d/next/Build/2022-07-25-09-48-43.gh-issue-95145.ZNS3dj.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
wasm32-wasi builds no longer depend on WASIX's pthread stubs. Python now has | ||
its own stubbed pthread API. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
#include "cpython/pthread_stubs.h" | ||
|
||
// mutex | ||
int | ||
pthread_mutex_init(pthread_mutex_t *restrict mutex, | ||
const pthread_mutexattr_t *restrict attr) | ||
{ | ||
return 0; | ||
} | ||
|
||
int | ||
pthread_mutex_destroy(pthread_mutex_t *mutex) | ||
{ | ||
return 0; | ||
} | ||
|
||
int | ||
pthread_mutex_trylock(pthread_mutex_t *mutex) | ||
{ | ||
return 0; | ||
} | ||
|
||
int | ||
pthread_mutex_lock(pthread_mutex_t *mutex) | ||
{ | ||
return 0; | ||
} | ||
|
||
int | ||
pthread_mutex_unlock(pthread_mutex_t *mutex) | ||
{ | ||
return 0; | ||
} | ||
|
||
// condition | ||
int | ||
pthread_cond_init(pthread_cond_t *restrict cond, | ||
const pthread_condattr_t *restrict attr) | ||
{ | ||
return 0; | ||
} | ||
|
||
PyAPI_FUNC(int)pthread_cond_destroy(pthread_cond_t *cond) | ||
{ | ||
return 0; | ||
} | ||
|
||
int | ||
pthread_cond_wait(pthread_cond_t *restrict cond, | ||
pthread_mutex_t *restrict mutex) | ||
{ | ||
return 0; | ||
} | ||
|
||
int | ||
pthread_cond_timedwait(pthread_cond_t *restrict cond, | ||
pthread_mutex_t *restrict mutex, | ||
const struct timespec *restrict abstime) | ||
{ | ||
return 0; | ||
} | ||
|
||
int | ||
pthread_cond_signal(pthread_cond_t *cond) | ||
{ | ||
return 0; | ||
} | ||
|
||
int | ||
pthread_condattr_init(pthread_condattr_t *attr) | ||
{ | ||
return 0; | ||
} | ||
|
||
int | ||
pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id) | ||
{ | ||
return 0; | ||
} | ||
|
||
// pthread | ||
int | ||
pthread_create(pthread_t *restrict thread, | ||
const pthread_attr_t *restrict attr, | ||
void *(*start_routine)(void *), | ||
void *restrict arg) | ||
{ | ||
return EAGAIN; | ||
} | ||
|
||
int | ||
pthread_detach(pthread_t thread) | ||
{ | ||
return 0; | ||
} | ||
|
||
PyAPI_FUNC(pthread_t) pthread_self(void) | ||
{ | ||
return 0; | ||
} | ||
|
||
int | ||
pthread_exit(void *retval) | ||
{ | ||
exit(0); | ||
} | ||
|
||
int | ||
pthread_attr_init(pthread_attr_t *attr) | ||
{ | ||
return 0; | ||
} | ||
|
||
int | ||
pthread_attr_setstacksize( | ||
pthread_attr_t *attr, size_t stacksize) | ||
{ | ||
return 0; | ||
} | ||
|
||
int | ||
pthread_attr_destroy(pthread_attr_t *attr) | ||
{ | ||
return 0; | ||
} | ||
|
||
// pthread_key | ||
typedef struct { | ||
bool in_use; | ||
void *value; | ||
} py_tls_entry; | ||
|
||
static py_tls_entry py_tls_entries[PTHREAD_KEYS_MAX] = {0}; | ||
|
||
int | ||
pthread_key_create(pthread_key_t *key, void (*destr_function)(void *)) | ||
{ | ||
if (!key) { | ||
return EINVAL; | ||
} | ||
if (destr_function != NULL) { | ||
Py_FatalError("pthread_key_create destructor is not supported"); | ||
} | ||
for (pthread_key_t idx = 0; idx < PTHREAD_KEYS_MAX; idx++) { | ||
if (!py_tls_entries[idx].in_use) { | ||
py_tls_entries[idx].in_use = true; | ||
*key = idx; | ||
return 0; | ||
} | ||
} | ||
return EAGAIN; | ||
} | ||
|
||
int | ||
pthread_key_delete(pthread_key_t key) | ||
{ | ||
if (key < 0 || key >= PTHREAD_KEYS_MAX || !py_tls_entries[key].in_use) { | ||
return EINVAL; | ||
} | ||
py_tls_entries[key].in_use = false; | ||
py_tls_entries[key].value = NULL; | ||
return 0; | ||
} | ||
|
||
|
||
void * | ||
pthread_getspecific(pthread_key_t key) { | ||
if (key < 0 || key >= PTHREAD_KEYS_MAX || !py_tls_entries[key].in_use) { | ||
return NULL; | ||
} | ||
return py_tls_entries[key].value; | ||
} | ||
|
||
int | ||
pthread_setspecific(pthread_key_t key, const void *value) | ||
{ | ||
if (key < 0 || key >= PTHREAD_KEYS_MAX || !py_tls_entries[key].in_use) { | ||
return EINVAL; | ||
} | ||
py_tls_entries[key].value = (void *)value; | ||
return 0; | ||
} | ||
|
||
// let thread_pthread define the Python API | ||
#include "thread_pthread.h" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.