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/libc_errno.h" |
20 | #include "src/__support/macros/config.h" |
21 | #include "src/__support/macros/optimization.h" |
22 | #include "src/__support/threads/thread.h" |
23 | |
24 | #include <pthread.h> // For pthread_* type definitions. |
25 | |
26 | namespace LIBC_NAMESPACE_DECL { |
27 | |
28 | static_assert(sizeof(pthread_t) == sizeof(LIBC_NAMESPACE::Thread), |
29 | "Mismatch between pthread_t and internal Thread." ); |
30 | |
31 | LLVM_LIBC_FUNCTION(int, pthread_create, |
32 | (pthread_t *__restrict th, |
33 | const pthread_attr_t *__restrict attr, |
34 | __pthread_start_t func, void *arg)) { |
35 | pthread_attr_t default_attr; |
36 | if (attr == nullptr) { |
37 | // We failed to initialize attributes (should be impossible) |
38 | if (LIBC_UNLIKELY(LIBC_NAMESPACE::pthread_attr_init(&default_attr) != 0)) |
39 | return EINVAL; |
40 | |
41 | attr = &default_attr; |
42 | } |
43 | |
44 | void *stack; |
45 | size_t stacksize, guardsize; |
46 | int detachstate; |
47 | |
48 | // As of writing this all the `pthread_attr_get*` functions always succeed. |
49 | if (LIBC_UNLIKELY( |
50 | LIBC_NAMESPACE::pthread_attr_getstack(attr, &stack, &stacksize) != 0)) |
51 | return EINVAL; |
52 | |
53 | if (LIBC_UNLIKELY( |
54 | LIBC_NAMESPACE::pthread_attr_getguardsize(attr, &guardsize) != 0)) |
55 | return EINVAL; |
56 | |
57 | if (LIBC_UNLIKELY( |
58 | LIBC_NAMESPACE::pthread_attr_getdetachstate(attr, &detachstate) != 0)) |
59 | return EINVAL; |
60 | |
61 | if (attr == &default_attr) |
62 | // Should we fail here? Its non-issue as the moment as pthread_attr_destroy |
63 | // can only succeed. |
64 | if (LIBC_UNLIKELY(LIBC_NAMESPACE::pthread_attr_destroy(&default_attr) != 0)) |
65 | return EINVAL; |
66 | |
67 | if (stacksize && stacksize < PTHREAD_STACK_MIN) |
68 | return EINVAL; |
69 | |
70 | if (guardsize % EXEC_PAGESIZE != 0) |
71 | return EINVAL; |
72 | |
73 | if (detachstate != PTHREAD_CREATE_DETACHED && |
74 | detachstate != PTHREAD_CREATE_JOINABLE) |
75 | return EINVAL; |
76 | |
77 | // Thread::run will check validity of the `stack` argument (stack alignment is |
78 | // universal, not sure a pthread requirement). |
79 | |
80 | auto *thread = reinterpret_cast<LIBC_NAMESPACE::Thread *>(th); |
81 | int result = thread->run(func, arg, stack, stacksize, guardsize, |
82 | detachstate == PTHREAD_CREATE_DETACHED); |
83 | if (result != 0 && result != EPERM && result != EINVAL) |
84 | return EAGAIN; |
85 | return result; |
86 | } |
87 | |
88 | } // namespace LIBC_NAMESPACE_DECL |
89 | |