1 /* Creating and controlling POSIX threads.
2    Copyright (C) 2010-2021 Free Software Foundation, Inc.
3 
4    This file is free software: you can redistribute it and/or modify
5    it under the terms of the GNU Lesser General Public License as
6    published by the Free Software Foundation; either version 2.1 of the
7    License, or (at your option) any later version.
8 
9    This file is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public License
15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
16 
17 /* Written by Paul Eggert, 2010, and Bruno Haible <bruno@clisp.org>, 2019.  */
18 
19 #include <config.h>
20 
21 /* Specification.  */
22 #include <pthread.h>
23 
24 #if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
25 # include "windows-thread.h"
26 #else
27 # include <stdlib.h>
28 #endif
29 
30 typedef void * (* pthread_main_function_t) (void *);
31 
32 #if ((defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS) || !HAVE_PTHREAD_H
33 
34 int
pthread_attr_init(pthread_attr_t * attr)35 pthread_attr_init (pthread_attr_t *attr)
36 {
37   *attr = PTHREAD_CREATE_JOINABLE;
38   return 0;
39 }
40 
41 int
pthread_attr_getdetachstate(const pthread_attr_t * attr,int * detachstatep)42 pthread_attr_getdetachstate (const pthread_attr_t *attr, int *detachstatep)
43 {
44   *detachstatep = *attr & (PTHREAD_CREATE_JOINABLE | PTHREAD_CREATE_DETACHED);
45   return 0;
46 }
47 
48 int
pthread_attr_setdetachstate(pthread_attr_t * attr,int detachstate)49 pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate)
50 {
51   if (!(detachstate == PTHREAD_CREATE_JOINABLE
52         || detachstate == PTHREAD_CREATE_DETACHED))
53     return EINVAL;
54   *attr ^= (*attr ^ detachstate)
55            & (PTHREAD_CREATE_JOINABLE | PTHREAD_CREATE_DETACHED);
56   return 0;
57 }
58 
59 int
pthread_attr_destroy(_GL_UNUSED pthread_attr_t * attr)60 pthread_attr_destroy (_GL_UNUSED pthread_attr_t *attr)
61 {
62   return 0;
63 }
64 
65 #endif
66 
67 #if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
68 /* Use Windows threads.  */
69 
70 int
pthread_create(pthread_t * threadp,const pthread_attr_t * attr,pthread_main_function_t mainfunc,void * arg)71 pthread_create (pthread_t *threadp, const pthread_attr_t *attr,
72                 pthread_main_function_t mainfunc, void *arg)
73 {
74   unsigned int glwthread_attr =
75     (attr != NULL
76      && (*attr & (PTHREAD_CREATE_JOINABLE | PTHREAD_CREATE_DETACHED))
77         != PTHREAD_CREATE_JOINABLE
78      ? GLWTHREAD_ATTR_DETACHED
79      : 0);
80   return glwthread_thread_create (threadp, glwthread_attr, mainfunc, arg);
81 }
82 
83 pthread_t
pthread_self(void)84 pthread_self (void)
85 {
86   return glwthread_thread_self ();
87 }
88 
89 int
pthread_equal(pthread_t thread1,pthread_t thread2)90 pthread_equal (pthread_t thread1, pthread_t thread2)
91 {
92   return thread1 == thread2;
93 }
94 
95 int
pthread_detach(pthread_t thread)96 pthread_detach (pthread_t thread)
97 {
98   return glwthread_thread_detach (thread);
99 }
100 
101 int
pthread_join(pthread_t thread,void ** valuep)102 pthread_join (pthread_t thread, void **valuep)
103 {
104   return glwthread_thread_join (thread, valuep);
105 }
106 
107 void
pthread_exit(void * value)108 pthread_exit (void *value)
109 {
110   glwthread_thread_exit (value);
111 }
112 
113 #elif HAVE_PTHREAD_H
114 /* Provide workarounds for POSIX threads.  */
115 
116 # if PTHREAD_CREATE_IS_INLINE
117 int
pthread_create(pthread_t * threadp,const pthread_attr_t * attr,pthread_main_function_t mainfunc,void * arg)118 pthread_create (pthread_t *threadp, const pthread_attr_t *attr,
119                 pthread_main_function_t mainfunc, void *arg)
120 #  undef pthread_create
121 {
122   return pthread_create (threadp, attr, mainfunc, arg);
123 }
124 
125 int
pthread_attr_init(pthread_attr_t * attr)126 pthread_attr_init (pthread_attr_t *attr)
127 #  undef pthread_attr_init
128 {
129   return pthread_attr_init (attr);
130 }
131 
132 # endif
133 
134 #else
135 /* Provide a dummy implementation for single-threaded applications.  */
136 
137 int
pthread_create(pthread_t * threadp,const pthread_attr_t * attr,pthread_main_function_t mainfunc,void * arg)138 pthread_create (pthread_t *threadp, const pthread_attr_t *attr,
139                 pthread_main_function_t mainfunc, void *arg)
140 {
141   /* The maximum number of threads is reached.  Do not create a thread.  */
142   return EAGAIN;
143 }
144 
145 pthread_t
pthread_self(void)146 pthread_self (void)
147 {
148   return 42;
149 }
150 
151 int
pthread_equal(pthread_t thread1,pthread_t thread2)152 pthread_equal (pthread_t thread1, pthread_t thread2)
153 {
154   return thread1 == thread2;
155 }
156 
157 int
pthread_detach(pthread_t thread)158 pthread_detach (pthread_t thread)
159 {
160   /* There are no joinable threads.  */
161   return EINVAL;
162 }
163 
164 int
pthread_join(pthread_t thread,void ** valuep)165 pthread_join (pthread_t thread, void **valuep)
166 {
167   /* There are no joinable threads.  */
168   return EINVAL;
169 }
170 
171 void
pthread_exit(void * value)172 pthread_exit (void *value)
173 {
174   /* There is just one thread, so the process exits.  */
175   exit (0);
176 }
177 
178 #endif
179