Backed out 4 changesets (bug 1879154) for causing bustage on nsUserCharacteristics...
[gecko.git] / mozglue / interposers / pthread_create_interposer.cpp
blob65f60c2d1bfdb6907990cd41b8f712f5b0dbead2
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include <algorithm>
7 #include <pthread.h>
8 #include <signal.h>
9 #include <stdlib.h>
10 #include <sys/mman.h>
12 #include "mozilla/Assertions.h"
13 #include "mozilla/DebugOnly.h"
15 #include "InterposerHelper.h"
17 using mozilla::DebugOnly;
19 struct SigAltStack {
20 void* mem;
21 size_t size;
24 struct PthreadCreateParams {
25 void* (*start_routine)(void*);
26 void* arg;
29 // Install the alternate signal stack, returns a pointer to the memory area we
30 // mapped to store the stack only if it was installed successfully, otherwise
31 // returns NULL.
32 static void* install_sig_alt_stack(size_t size) {
33 void* alt_stack_mem = mmap(nullptr, size, PROT_READ | PROT_WRITE,
34 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
35 if (alt_stack_mem) {
36 stack_t alt_stack = {
37 .ss_sp = alt_stack_mem,
38 .ss_flags = 0,
39 .ss_size = size,
42 int rv = sigaltstack(&alt_stack, nullptr);
43 if (rv == 0) {
44 return alt_stack_mem;
47 rv = munmap(alt_stack_mem, size);
48 MOZ_ASSERT(rv == 0);
51 return nullptr;
54 // Uninstall the alternate signal handler and unmaps it. Does nothing if
55 // alt_stack_mem is NULL.
56 static void uninstall_sig_alt_stack(void* alt_stack_ptr) {
57 SigAltStack* alt_stack = static_cast<SigAltStack*>(alt_stack_ptr);
58 if (alt_stack->mem) {
59 stack_t disable_alt_stack = {};
60 disable_alt_stack.ss_flags = SS_DISABLE;
61 DebugOnly<int> rv = sigaltstack(&disable_alt_stack, nullptr);
62 MOZ_ASSERT(rv == 0);
63 rv = munmap(alt_stack->mem, alt_stack->size);
64 MOZ_ASSERT(rv == 0);
68 // This replaces the routine passed to pthread_create() when a thread is
69 // started, it handles the alternate signal stack and calls the thread's
70 // actual routine.
71 void* set_alt_signal_stack_and_start(PthreadCreateParams* params) {
72 void* (*start_routine)(void*) = params->start_routine;
73 void* arg = params->arg;
74 free(params);
76 void* thread_rv = nullptr;
77 static const size_t kSigStackSize = std::max(size_t(16384), size_t(SIGSTKSZ));
78 void* alt_stack_mem = install_sig_alt_stack(kSigStackSize);
79 SigAltStack alt_stack{alt_stack_mem, kSigStackSize};
80 pthread_cleanup_push(uninstall_sig_alt_stack, &alt_stack);
81 thread_rv = start_routine(arg);
82 pthread_cleanup_pop(1);
84 return thread_rv;
87 extern "C" {
88 // This interposer replaces libpthread's pthread_create() so that we can
89 // inject an alternate signal stack in every new thread.
90 MFBT_API int pthread_create(pthread_t* thread, const pthread_attr_t* attr,
91 void* (*start_routine)(void*), void* arg) {
92 static const auto real_pthread_create = GET_REAL_SYMBOL(pthread_create);
94 PthreadCreateParams* params =
95 (PthreadCreateParams*)malloc(sizeof(PthreadCreateParams));
96 params->start_routine = start_routine;
97 params->arg = arg;
99 int result = real_pthread_create(
100 thread, attr, (void* (*)(void*))set_alt_signal_stack_and_start, params);
102 if (result != 0) {
103 free(params);
106 return result;