Skip to content

Commit

Permalink
Split the pthread library out of libc
Browse files Browse the repository at this point in the history
  • Loading branch information
sbc100 committed Oct 18, 2024
1 parent 10cb9d4 commit b4da8b0
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 100 deletions.
4 changes: 4 additions & 0 deletions embuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@
'libGL-webgl2-ofb-getprocaddr',
'libGL-ww-getprocaddr',
'libhtml5',
'libpthread',
'libpthread-stub',
'libpthread-debug',
'libpthread-debug-stub',
'libsockets',
'libsockets-ww',
'libstubs',
Expand Down
6 changes: 3 additions & 3 deletions test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4625,10 +4625,10 @@ def test_dylink_postsets_chunking(self):

@with_dylink_reversed
@parameterized({
'libcxx': ('libc,libc++,libmalloc,libc++abi',),
'libcxx': ('libc,libpthread,libc++,libmalloc,libc++abi',),
'all': ('1',),
'missing': ('libc,libmalloc,libc++abi', False, False, False),
'missing_assertions': ('libc,libmalloc,libc++abi', False, False, True),
'missing': ('libc,libpthread,libmalloc,libc++abi', False, False, False),
'missing_assertions': ('libc,libpthread,libmalloc,libc++abi', False, False, True),
})
def test_dylink_syslibs(self, syslibs, expect_pass=True, with_reversed=True, assertions=True):
# one module uses libcxx, need to force its inclusion when it isn't the main
Expand Down
13 changes: 7 additions & 6 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -5998,9 +5998,9 @@ def test_bad_lookup(self):
# partial list, but ok since we grab them as needed
'parial': [{'EMCC_FORCE_STDLIBS': 'libc++'}, False],
# fail! not enough stdlibs
'partial_only': [{'EMCC_FORCE_STDLIBS': 'libc++,libc,libc++abi', 'EMCC_ONLY_FORCED_STDLIBS': '1'}, True],
'partial_only': [{'EMCC_FORCE_STDLIBS': 'libc++,libc,libpthread,libc++abi', 'EMCC_ONLY_FORCED_STDLIBS': '1'}, True],
# force all the needed stdlibs, so this works even though we ignore the input file
'full_only': [{'EMCC_FORCE_STDLIBS': 'libc,libc++abi,libc++,libmalloc', 'EMCC_ONLY_FORCED_STDLIBS': '1'}, False],
'full_only': [{'EMCC_FORCE_STDLIBS': 'libc,libpthread,libc++abi,libc++,libmalloc', 'EMCC_ONLY_FORCED_STDLIBS': '1'}, False],
})
def test_only_force_stdlibs(self, env, fail):
cmd = [EMXX, test_file('hello_libcxx.cpp')]
Expand Down Expand Up @@ -6031,7 +6031,7 @@ def test_only_force_stdlibs_2(self):
}
}
''')
with env_modify({'EMCC_FORCE_STDLIBS': 'libc,libc++abi,libc++,libmalloc', 'EMCC_ONLY_FORCED_STDLIBS': '1'}):
with env_modify({'EMCC_FORCE_STDLIBS': 'libc,libpthread,libc++abi,libc++,libmalloc', 'EMCC_ONLY_FORCED_STDLIBS': '1'}):
self.run_process([EMXX, 'src.cpp', '-sDISABLE_EXCEPTION_CATCHING=0'])
self.assertContained('Caught exception: std::exception', self.run_js('a.out.js'))

Expand Down Expand Up @@ -12277,10 +12277,10 @@ def test_nostdlib(self):
self.assertContained(err, self.expect_fail([EMCC, test_file('unistd/close.c'), '-nodefaultlibs']))

# Build again but with explit system libraries
libs = ['-lc', '-lcompiler_rt']
libs = ['-lc', '-lpthread', '-lcompiler_rt']
self.run_process([EMCC, test_file('unistd/close.c'), '-nostdlib'] + libs)
self.run_process([EMCC, test_file('unistd/close.c'), '-nodefaultlibs'] + libs)
self.run_process([EMCC, test_file('unistd/close.c'), '-nolibc', '-lc'])
self.run_process([EMCC, test_file('unistd/close.c'), '-nolibc', '-lc', '-lpthread'])
self.run_process([EMCC, test_file('unistd/close.c'), '-nostartfiles'])

def test_argument_match(self):
Expand Down Expand Up @@ -13174,12 +13174,13 @@ def test_offset_convertor_plus_wasm2js(self):

def test_standard_library_mapping(self):
# Test the `-l` flags on the command line get mapped the correct libraries variant
libs = ['-lc', '-lbulkmemory', '-lcompiler_rt', '-lmalloc']
libs = ['-lc', '-lpthread', '-lbulkmemory', '-lcompiler_rt', '-lmalloc']
err = self.run_process([EMCC, test_file('hello_world.c'), '-pthread', '-nodefaultlibs', '-v'] + libs, stderr=PIPE).stderr

# Check that the linker was run with `-mt` variants because `-pthread` was passed.
self.assertContained(' -lc-mt-debug ', err)
self.assertContained(' -ldlmalloc-mt ', err)
self.assertContained(' -lpthread-debug ', err)
self.assertContained(' -lcompiler_rt-mt ', err)

def test_explicit_gl_linking(self):
Expand Down
1 change: 0 additions & 1 deletion tools/link.py
Original file line number Diff line number Diff line change
Expand Up @@ -2721,7 +2721,6 @@ def map_to_js_libs(library_name):
'dl': [],
'm': [],
'rt': [],
'pthread': [],
# This is the name of GNU's C++ standard library. We ignore it here
# for compatibility with GNU toolchains.
'stdc++': [],
Expand Down
224 changes: 134 additions & 90 deletions tools/system_libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,138 @@ class libnoexit(Library):
src_files = ['atexit_dummy.c']


class libpthread(MuslInternalLibrary,
DebugLibrary,
AsanInstrumentedLibrary):
name = 'libpthread'
# See libc
cflags = ['-Os', '-fno-inline-functions', '-fno-builtin']
cflags += ['-Wno-unused-but-set-variable',
'-Wno-unused-variable',
'-Wno-shift-op-parentheses',
'-Wno-unused-label',
'-Wno-logical-op-parentheses',
'-Wno-bitwise-op-parentheses']

def __init__(self, **kwargs):
self.is_stub = kwargs.pop('stub')
super().__init__(**kwargs)

def get_cflags(self):
cflags = super().get_cflags()
if not self.is_stub:
cflags += ['-pthread']
return cflags

def get_base_name(self):
name = super().get_base_name()
if self.is_stub:
name += '-stub'
return name

@classmethod
def vary_on(cls):
return super().vary_on() + ['stub']

@classmethod
def get_default_variation(cls, **kwargs):
return super().get_default_variation(stub=not settings.PTHREADS, **kwargs)

def get_files(self):
files = files_in_path(
path='system/lib/pthread',
filenames=['thread_profiler.c'])

if self.is_stub:
# Include just a subset of the thread directory
files += files_in_path(
path='system/lib/libc/musl/src/thread',
filenames=[
'pthread_self.c',
'pthread_cleanup_push.c',
'pthread_attr_init.c',
'pthread_attr_destroy.c',
'pthread_attr_get.c',
'pthread_attr_setdetachstate.c',
'pthread_attr_setguardsize.c',
'pthread_attr_setinheritsched.c',
'pthread_attr_setschedparam.c',
'pthread_attr_setschedpolicy.c',
'pthread_attr_setscope.c',
'pthread_attr_setstack.c',
'pthread_attr_setstacksize.c',
'pthread_getconcurrency.c',
'pthread_getcpuclockid.c',
'pthread_getschedparam.c',
'pthread_setschedprio.c',
'pthread_setconcurrency.c',
'default_attr.c',
# C11 thread library functions
'call_once.c',
'tss_create.c',
'tss_delete.c',
'tss_set.c',
'cnd_broadcast.c',
'cnd_destroy.c',
'cnd_init.c',
'cnd_signal.c',
'cnd_timedwait.c',
'cnd_wait.c',
'mtx_destroy.c',
'mtx_init.c',
'mtx_lock.c',
'mtx_timedlock.c',
'mtx_trylock.c',
'mtx_unlock.c',
'thrd_create.c',
'thrd_exit.c',
'thrd_join.c',
'thrd_sleep.c',
'thrd_yield.c',
])
files += files_in_path(
path='system/lib/pthread',
filenames=[
'library_pthread_stub.c',
'pthread_self_stub.c',
'proxying_stub.c',
])
else:
files += glob_in_path(
path='system/lib/libc/musl/src/thread',
glob_pattern='*.c',
excludes=[
'clone.c',
'pthread_create.c',
'pthread_kill.c', 'pthread_sigmask.c',
'__set_thread_area.c', 'synccall.c',
'__syscall_cp.c', '__tls_get_addr.c',
'__unmapself.c',
# Empty files, simply ignore them.
'syscall_cp.c', 'tls.c',
# TODO: Support these. See #12216.
'pthread_setname_np.c',
'pthread_getname_np.c',
])
files += files_in_path(
path='system/lib/pthread',
filenames=[
'library_pthread.c',
'em_task_queue.c',
'proxying.c',
'proxying_legacy.c',
'thread_mailbox.c',
'pthread_create.c',
'pthread_kill.c',
'emscripten_thread_init.c',
'emscripten_thread_state.S',
'emscripten_futex_wait.c',
'emscripten_futex_wake.c',
'emscripten_yield.c',
])
return files


class libc(MuslInternalLibrary,
DebugLibrary,
AsanInstrumentedLibrary,
Expand Down Expand Up @@ -1088,7 +1220,7 @@ def get_files(self):
ignore = [
'ipc', 'passwd', 'signal', 'sched', 'time', 'linux',
'aio', 'exit', 'legacy', 'mq', 'setjmp',
'ldso', 'malloc'
'ldso', 'malloc', 'thread'
]

# individual files
Expand All @@ -1111,91 +1243,6 @@ def get_files(self):

ignore += LIBC_SOCKETS

if self.is_mt:
ignore += [
'clone.c',
'pthread_create.c',
'pthread_kill.c', 'pthread_sigmask.c',
'__set_thread_area.c', 'synccall.c',
'__syscall_cp.c', '__tls_get_addr.c',
'__unmapself.c',
# Empty files, simply ignore them.
'syscall_cp.c', 'tls.c',
# TODO: Support these. See #12216.
'pthread_setname_np.c',
'pthread_getname_np.c',
]
libc_files += files_in_path(
path='system/lib/pthread',
filenames=[
'library_pthread.c',
'em_task_queue.c',
'proxying.c',
'proxying_legacy.c',
'thread_mailbox.c',
'pthread_create.c',
'pthread_kill.c',
'emscripten_thread_init.c',
'emscripten_thread_state.S',
'emscripten_futex_wait.c',
'emscripten_futex_wake.c',
'emscripten_yield.c',
])
else:
ignore += ['thread']
libc_files += files_in_path(
path='system/lib/libc/musl/src/thread',
filenames=[
'pthread_self.c',
'pthread_cleanup_push.c',
'pthread_attr_init.c',
'pthread_attr_destroy.c',
'pthread_attr_get.c',
'pthread_attr_setdetachstate.c',
'pthread_attr_setguardsize.c',
'pthread_attr_setinheritsched.c',
'pthread_attr_setschedparam.c',
'pthread_attr_setschedpolicy.c',
'pthread_attr_setscope.c',
'pthread_attr_setstack.c',
'pthread_attr_setstacksize.c',
'pthread_getconcurrency.c',
'pthread_getcpuclockid.c',
'pthread_getschedparam.c',
'pthread_setschedprio.c',
'pthread_setconcurrency.c',
'default_attr.c',
# C11 thread library functions
'call_once.c',
'tss_create.c',
'tss_delete.c',
'tss_set.c',
'cnd_broadcast.c',
'cnd_destroy.c',
'cnd_init.c',
'cnd_signal.c',
'cnd_timedwait.c',
'cnd_wait.c',
'mtx_destroy.c',
'mtx_init.c',
'mtx_lock.c',
'mtx_timedlock.c',
'mtx_trylock.c',
'mtx_unlock.c',
'thrd_create.c',
'thrd_exit.c',
'thrd_join.c',
'thrd_sleep.c',
'thrd_yield.c',
])
libc_files += files_in_path(
path='system/lib/pthread',
filenames=[
'library_pthread_stub.c',
'pthread_self_stub.c',
'proxying_stub.c',
])

# These files are in libc directories, but only built in libc_optz.
ignore += [
'pow_small.c', 'log_small.c', 'log2_small.c'
Expand Down Expand Up @@ -1307,10 +1354,6 @@ def get_files(self):
if settings.RELOCATABLE:
libc_files += files_in_path(path='system/lib/libc', filenames=['dynlink.c'])

libc_files += files_in_path(
path='system/lib/pthread',
filenames=['thread_profiler.c'])

libc_files += glob_in_path('system/lib/libc/compat', '*.c')

# Check for missing file in non_lto_files list. Do this here
Expand Down Expand Up @@ -2372,6 +2415,7 @@ def add_sanitizer_libs():
if settings.ALLOW_UNIMPLEMENTED_SYSCALLS:
add_library('libstubs')
if '-nolibc' not in args:
add_library('libpthread')
if not settings.EXIT_RUNTIME:
add_library('libnoexit')
add_library('libc')
Expand Down

0 comments on commit b4da8b0

Please sign in to comment.