1 | //===-- Linux implementation of the pthread_create function ---------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "pthread_create.h" |
10 | |
11 | #include "pthread_attr_destroy.h" |
12 | #include "pthread_attr_init.h" |
13 | |
14 | #include "pthread_attr_getdetachstate.h" |
15 | #include "pthread_attr_getguardsize.h" |
16 | #include "pthread_attr_getstack.h" |
17 | |
18 | #include "src/__support/common.h" |
19 | #include "src/__support/macros/optimization.h" |
20 | #include "src/__support/threads/thread.h" |
21 | |
22 | #include <errno.h> |
23 | #include <pthread.h> // For pthread_* type definitions. |
24 | |
25 | namespace LIBC_NAMESPACE { |
26 | |
27 | static_assert(sizeof(pthread_t) == sizeof(LIBC_NAMESPACE::Thread), |
28 | "Mismatch between pthread_t and internal Thread." ); |
29 | |
30 | LLVM_LIBC_FUNCTION(int, pthread_create, |
31 | (pthread_t *__restrict th, |
32 | const pthread_attr_t *__restrict attr, |
33 | __pthread_start_t func, void *arg)) { |
34 | pthread_attr_t default_attr; |
35 | if (attr == nullptr) { |
36 | // We failed to initialize attributes (should be impossible) |
37 | if (LIBC_UNLIKELY(LIBC_NAMESPACE::pthread_attr_init(&default_attr) != 0)) |
38 | return EINVAL; |
39 | |
40 | attr = &default_attr; |
41 | } |
42 | |
43 | void *stack; |
44 | size_t stacksize, guardsize; |
45 | int detachstate; |
46 | |
47 | // As of writing this all the `pthread_attr_get*` functions always succeed. |
48 | if (LIBC_UNLIKELY( |
49 | LIBC_NAMESPACE::pthread_attr_getstack(attr, &stack, &stacksize) != 0)) |
50 | return EINVAL; |
51 | |
52 | if (LIBC_UNLIKELY( |
53 | LIBC_NAMESPACE::pthread_attr_getguardsize(attr, &guardsize) != 0)) |
54 | return EINVAL; |
55 | |
56 | if (LIBC_UNLIKELY( |
57 | LIBC_NAMESPACE::pthread_attr_getdetachstate(attr, &detachstate) != 0)) |
58 | return EINVAL; |
59 | |
60 | if (attr == &default_attr) |
61 | // Should we fail here? Its non-issue as the moment as pthread_attr_destroy |
62 | // can only succeed. |
63 | if (LIBC_UNLIKELY(LIBC_NAMESPACE::pthread_attr_destroy(&default_attr) != 0)) |
64 | return EINVAL; |
65 | |
66 | if (stacksize && stacksize < PTHREAD_STACK_MIN) |
67 | return EINVAL; |
68 | |
69 | if (guardsize % EXEC_PAGESIZE != 0) |
70 | return EINVAL; |
71 | |
72 | if (detachstate != PTHREAD_CREATE_DETACHED && |
73 | detachstate != PTHREAD_CREATE_JOINABLE) |
74 | return EINVAL; |
75 | |
76 | // Thread::run will check validity of the `stack` argument (stack alignment is |
77 | // universal, not sure a pthread requirement). |
78 | |
79 | auto *thread = reinterpret_cast<LIBC_NAMESPACE::Thread *>(th); |
80 | int result = thread->run(func, arg, stack, stacksize, guardsize, |
81 | detachstate == PTHREAD_CREATE_DETACHED); |
82 | if (result != 0 && result != EPERM && result != EINVAL) |
83 | return EAGAIN; |
84 | return result; |
85 | } |
86 | |
87 | } // namespace LIBC_NAMESPACE |
88 | |