Commit for Maxim <3
[build.git] / thread.c
blob3c8d703ae83f32afb80e86100f86085985c561d9
1 /* thread.c -- system-independent thread types and functions.
3 Copyright (C) 2022 Sergey Sushilin <sergeysushilin@protonmail.com>
5 This file is part of Build.
7 Build is free software: you can redistribute it and/or
8 modify it under the terms of either the GNU General Public License
9 as published by the Free Software Foundation;
10 either version 2 of the License, or version 3 of the License,
11 or both in parallel, as here.
13 Build is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received copies of the GNU General Public License
19 version 2 and 3 along with this program.
20 If not, see http://www.gnu.org/licenses/. */
22 #ifndef _WIN32
23 # include <errno.h>
24 # include <string.h>
25 #endif
27 #include "diagnostic.h"
28 #include "thread.h"
29 #include "uniqstr.h"
31 #ifdef _WIN32
32 static NODISCARD uniqstr RETURNS_NONNULL
33 GetLastErrorString (void)
35 DWORD err = GetLastError ();
36 char *msg_buf;
37 uniqstr msg;
39 FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER
40 | FORMAT_MESSAGE_FROM_SYSTEM
41 | FORMAT_MESSAGE_IGNORE_INSERTS,
42 NULL,
43 err,
44 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
45 (char *) &msg_buf,
47 NULL);
48 msg = uniqstr_new (msg_buf);
49 LocalFree (msg_buf);
50 return msg;
52 #endif
54 bool
55 thread_create (struct thread *tid, thread_start_t start, void *arg)
57 #ifdef _WIN32
58 tid->thread = CreateThread (NULL, /* Default security attributes. */
59 0, /* Default stack size. */
60 start, /* Thread function. */
61 arg, /* Thread function arguments. */
62 0, /* Default creation flags. */
63 NULL); /* Receive thread identifier. */
65 if (UNLIKELY (tid->thread == NULL))
67 error (_("failed to create thread: %s"), GetLastErrorString ());
68 return false;
71 return true;
72 #else
73 if (UNLIKELY (pthread_create (&tid->thread, NULL, start, arg) != 0))
75 error (_("failed to create thread: %s"), strerror (errno));
76 return false;
79 return true;
80 #endif
83 bool
84 thread_join (struct thread *tid, void **result)
86 #ifdef _WIN32
87 DWORD code;
89 if (UNLIKELY (WaitForSingleObject (tid->thread, INFINITE) != WAIT_OBJECT_0))
91 error (_("failed to join thread: %s"), GetLastErrorString ());
92 return false;
95 if (UNLIKELY (!GetExitCodeThread (tid->thread, &code)))
97 error (_("failed to get return value of thread: %s"), GetLastErrorString ());
98 *result = NULL;
99 return false;
102 *result = (void *) code;
103 return true;
104 #else
105 if (UNLIKELY (pthread_join (tid->thread, result) != 0))
107 error (_("failed to join thread: %s"), strerror (errno));
108 return false;
111 return true;
112 #endif
115 void
116 thread_exit (void *result)
118 #ifdef _WIN32
119 ExitThread ((DWORD) result);
120 #else
121 pthread_exit (result);
122 #endif
125 bool
126 mutex_create (struct mutex *mutex)
128 #ifdef _WIN32
129 mutex->mutex = CreateMutex (NULL, FALSE, NULL);
131 if (UNLIKELY (mutex->mutex == NULL))
133 error (_("failed to create mutex: %s"), strerror (errno));
134 return false;
137 return true;
138 #else
139 if (UNLIKELY (pthread_mutex_init (&mutex->mutex, NULL) != 0))
141 error (_("failed to create mutex: %s"), strerror (errno));
142 return false;
145 return true;
146 #endif
149 void
150 mutex_acquire (struct mutex *mutex)
152 /* TODO: abort on failure? */
153 #ifdef _WIN32
154 if (UNLIKELY (WaitForSingleObject (mutex->mutex, INFINITE) != WAIT_OBJECT_0))
156 error (_("failed to join thread: %s"), GetLastErrorString ());
158 #else
159 if (UNLIKELY (pthread_mutex_lock (&mutex->mutex) != 0))
161 error (_("failed to acquire mutex: %s"), strerror (errno));
163 #endif
166 void
167 mutex_release (struct mutex *mutex)
169 /* TODO: abort on failure? */
170 #ifdef _WIN32
171 if (UNLIKELY (!ReleaseMutex (mutex->mutex)))
173 error (_("failed to release mutex: %s"), strerror (errno));
174 return;
176 #else
177 if (UNLIKELY (pthread_mutex_unlock (&mutex->mutex) != 0))
179 error (_("failed to release mutex: %s"), strerror (errno));
180 return;
182 #endif
185 void
186 mutex_destroy (struct mutex *mutex)
188 #ifdef _WIN32
189 CloseHandle (mutex->mutex);
190 #else
191 pthread_mutex_destroy (&mutex->mutex);
192 #endif