xref: /llvm-project/libc/src/pthread/pthread_create.cpp (revision 46944b0cbc9a9d8daad0182c40fcd3560bc9ca35)
170c8d12bSSiva Chandra Reddy //===-- Linux implementation of the pthread_create function ---------------===//
270c8d12bSSiva Chandra Reddy //
370c8d12bSSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
470c8d12bSSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
570c8d12bSSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
670c8d12bSSiva Chandra Reddy //
770c8d12bSSiva Chandra Reddy //===----------------------------------------------------------------------===//
870c8d12bSSiva Chandra Reddy 
970c8d12bSSiva Chandra Reddy #include "pthread_create.h"
1070c8d12bSSiva Chandra Reddy 
116a185718SNoah Goldstein #include "pthread_attr_destroy.h"
126a185718SNoah Goldstein #include "pthread_attr_init.h"
136a185718SNoah Goldstein 
146a185718SNoah Goldstein #include "pthread_attr_getdetachstate.h"
156a185718SNoah Goldstein #include "pthread_attr_getguardsize.h"
166a185718SNoah Goldstein #include "pthread_attr_getstack.h"
176a185718SNoah Goldstein 
1870c8d12bSSiva Chandra Reddy #include "src/__support/common.h"
195ff3ff33SPetr Hosek #include "src/__support/macros/config.h"
206a185718SNoah Goldstein #include "src/__support/macros/optimization.h"
2170c8d12bSSiva Chandra Reddy #include "src/__support/threads/thread.h"
22*46944b0cSJob Henandez Lara #include "src/errno/libc_errno.h"
2370c8d12bSSiva Chandra Reddy 
2470c8d12bSSiva Chandra Reddy #include <pthread.h> // For pthread_* type definitions.
2570c8d12bSSiva Chandra Reddy 
265ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL {
2770c8d12bSSiva Chandra Reddy 
28b6bc9d72SGuillaume Chatelet static_assert(sizeof(pthread_t) == sizeof(LIBC_NAMESPACE::Thread),
29f4580c6dSSiva Chandra Reddy               "Mismatch between pthread_t and internal Thread.");
3070c8d12bSSiva Chandra Reddy 
3170c8d12bSSiva Chandra Reddy LLVM_LIBC_FUNCTION(int, pthread_create,
326a185718SNoah Goldstein                    (pthread_t *__restrict th,
336a185718SNoah Goldstein                     const pthread_attr_t *__restrict attr,
3470c8d12bSSiva Chandra Reddy                     __pthread_start_t func, void *arg)) {
356a185718SNoah Goldstein   pthread_attr_t default_attr;
366a185718SNoah Goldstein   if (attr == nullptr) {
376a185718SNoah Goldstein     // We failed to initialize attributes (should be impossible)
38b6bc9d72SGuillaume Chatelet     if (LIBC_UNLIKELY(LIBC_NAMESPACE::pthread_attr_init(&default_attr) != 0))
396a185718SNoah Goldstein       return EINVAL;
406a185718SNoah Goldstein 
416a185718SNoah Goldstein     attr = &default_attr;
426a185718SNoah Goldstein   }
436a185718SNoah Goldstein 
446a185718SNoah Goldstein   void *stack;
456a185718SNoah Goldstein   size_t stacksize, guardsize;
466a185718SNoah Goldstein   int detachstate;
476a185718SNoah Goldstein 
486a185718SNoah Goldstein   // As of writing this all the `pthread_attr_get*` functions always succeed.
496a185718SNoah Goldstein   if (LIBC_UNLIKELY(
50b6bc9d72SGuillaume Chatelet           LIBC_NAMESPACE::pthread_attr_getstack(attr, &stack, &stacksize) != 0))
516a185718SNoah Goldstein     return EINVAL;
526a185718SNoah Goldstein 
536a185718SNoah Goldstein   if (LIBC_UNLIKELY(
54b6bc9d72SGuillaume Chatelet           LIBC_NAMESPACE::pthread_attr_getguardsize(attr, &guardsize) != 0))
55b6bc9d72SGuillaume Chatelet     return EINVAL;
56b6bc9d72SGuillaume Chatelet 
57b6bc9d72SGuillaume Chatelet   if (LIBC_UNLIKELY(
58b6bc9d72SGuillaume Chatelet           LIBC_NAMESPACE::pthread_attr_getdetachstate(attr, &detachstate) != 0))
596a185718SNoah Goldstein     return EINVAL;
606a185718SNoah Goldstein 
616a185718SNoah Goldstein   if (attr == &default_attr)
626a185718SNoah Goldstein     // Should we fail here? Its non-issue as the moment as pthread_attr_destroy
636a185718SNoah Goldstein     // can only succeed.
64b6bc9d72SGuillaume Chatelet     if (LIBC_UNLIKELY(LIBC_NAMESPACE::pthread_attr_destroy(&default_attr) != 0))
656a185718SNoah Goldstein       return EINVAL;
666a185718SNoah Goldstein 
676a185718SNoah Goldstein   if (stacksize && stacksize < PTHREAD_STACK_MIN)
686a185718SNoah Goldstein     return EINVAL;
696a185718SNoah Goldstein 
706a185718SNoah Goldstein   if (guardsize % EXEC_PAGESIZE != 0)
716a185718SNoah Goldstein     return EINVAL;
726a185718SNoah Goldstein 
736a185718SNoah Goldstein   if (detachstate != PTHREAD_CREATE_DETACHED &&
746a185718SNoah Goldstein       detachstate != PTHREAD_CREATE_JOINABLE)
756a185718SNoah Goldstein     return EINVAL;
766a185718SNoah Goldstein 
776a185718SNoah Goldstein   // Thread::run will check validity of the `stack` argument (stack alignment is
786a185718SNoah Goldstein   // universal, not sure a pthread requirement).
796a185718SNoah Goldstein 
80b6bc9d72SGuillaume Chatelet   auto *thread = reinterpret_cast<LIBC_NAMESPACE::Thread *>(th);
816a185718SNoah Goldstein   int result = thread->run(func, arg, stack, stacksize, guardsize,
826a185718SNoah Goldstein                            detachstate == PTHREAD_CREATE_DETACHED);
836a185718SNoah Goldstein   if (result != 0 && result != EPERM && result != EINVAL)
8470c8d12bSSiva Chandra Reddy     return EAGAIN;
8570c8d12bSSiva Chandra Reddy   return result;
8670c8d12bSSiva Chandra Reddy }
8770c8d12bSSiva Chandra Reddy 
885ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL
89