XCP_SIM
threads.c
1 /*
2  * BlueParrot XCP
3  *
4  * (C) 2021-2022 by Christoph Schueler <github.com/Christoph2,
5  * cpu12.gems@googlemail.com>
6  *
7  * All Rights Reserved
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  * s. FLOSS-EXCEPTION.txt
24  */
25 
26 #if defined(_WIN32)
27 
28 #include <process.h>
29 #include <windows.h>
30 
31 #else
32 #include <pthread.h>
33 #include <sched.h>
34 #endif
35 
36 #include <errno.h>
37 #include <signal.h>
38 #include <stdbool.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 
42 /*
43 ** NOTE: Atomics require at least C11.
44 */
45 #if !defined(__STDC_NO_ATOMICS__)
46 
47 #if defined(_MSC_VER)
48 typedef bool atomic_bool;
49 #else
50 #include <stdatomic.h>
51 #endif
52 
53 #endif /* __STDC_NO_ATOMICS__ */
54 
56 #include "xcp.h"
57 #include "xcp_hw.h"
58 #include "xcp_threads.h"
61 #define XCP_THREAD (0)
62 #define UI_THREAD (1)
63 #define APP_THREAD (2)
64 #define TL_THREAD (3)
65 
66 #define NUM_THREADS (4)
67 
68 typedef void (*XcpThrd_ThreadFuncType)(void *);
69 
70 #if defined(_WIN32)
71 typedef HANDLE XcpThrd_ThreadType;
72 #else
73 typedef pthread_t XcpThrd_ThreadType;
74 #endif
75 
76 XcpThrd_ThreadType threads[NUM_THREADS];
77 
78 static void XcpThrd_CreateThread(XcpThrd_ThreadType *thrd,
79  XcpThrd_ThreadFuncType func);
80 
81 static void XcpThrd_SetAffinity(XcpThrd_ThreadType thrd, int cpu);
82 
83 #if defined(__STDC_NO_ATOMICS__)
84 static bool XcpThrd_ShuttingDown;
85 #else
86 static atomic_bool XcpThrd_ShuttingDown;
87 #endif /* __STDC_NO_ATOMICS__ */
88 
89 void bye(void);
90 
91 static void XcpThrd_CreateThread(XcpThrd_ThreadType *thrd,
92  XcpThrd_ThreadFuncType func) {
93 #if defined(_WIN32)
94  XcpThrd_ThreadType res;
95  res = (HANDLE)_beginthread(func, 0, NULL);
96  CopyMemory(thrd, &res, sizeof(XcpThrd_ThreadType));
97  XcpThrd_SetAffinity(res, 1);
98 #else
99  pthread_create(thrd, NULL, func, NULL);
100  XcpThrd_SetAffinity(thrd, 1);
101 #endif
102 }
103 
104 void XcpThrd_RunThreads(void) {
105  atexit(bye);
106 
107  XcpThrd_CreateThread(&threads[UI_THREAD], XcpTerm_Thread);
108  XcpThrd_CreateThread(&threads[TL_THREAD], XcpTl_Thread);
109  XcpThrd_CreateThread(&threads[XCP_THREAD], Xcp_Thread);
110 #if defined(_WIN32)
111  WaitForSingleObject(threads[UI_THREAD], INFINITE);
112  XcpThrd_ShutDown();
113 #else
114  pthread_join(threads[UI_THREAD], NULL);
115  XcpThrd_ShutDown();
116  pthread_kill(threads[TL_THREAD], SIGINT);
117  pthread_kill(threads[XCP_THREAD], SIGINT);
118 #endif
119 }
120 
121 void XcpThrd_Exit(void) {
122 #if defined(_WIN32)
123  ExitThread(0);
124 #else
125  pthread_exit(NULL);
126 #endif
127 }
128 
129 void *Xcp_Thread(void *param) {
130  XCP_UNREFERENCED_PARAMETER(param);
131  XCP_FOREVER { Xcp_MainFunction(); }
132  return NULL;
133 }
134 
135 void XcpThrd_EnableAsyncCancellation(void) {
136 #if defined(_WIN32)
137 
138 #else
139  int res;
140 
141  res = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
142  if (res != 0) {
143  XcpHw_ErrorMsg("pthread_setcancelstate()", errno);
144  }
145 #endif
146 }
147 
148 void XcpThrd_ShutDown(void) {
149  int res;
150 
151  printf("Shutdown RQ.\n");
152  if (XcpThrd_IsShuttingDown()) {
153  return;
154  }
155  // Due to blocking accept().
156 #if defined(_WIN32)
157  res = TerminateThread(threads[TL_THREAD], 0);
158  if (!res) {
159  XcpHw_ErrorMsg("TerminateThread", GetLastError());
160  }
161 #else
162  res = pthread_cancel(threads[TL_THREAD]);
163  if (res != 0) {
164  XcpHw_ErrorMsg("pthread_cancel()", errno);
165  }
166 #endif
167  XcpThrd_ShuttingDown = true;
168 }
169 
170 bool XcpThrd_IsShuttingDown(void) { return XcpThrd_ShuttingDown; }
171 
172 void bye(void) { printf("Exiting program.\n"); }
173 
174 static void XcpThrd_SetAffinity(XcpThrd_ThreadType thrd, int cpu) {
175 #if defined(_WIN32)
176  if (SetThreadAffinityMask(thrd, cpu) == 0) {
177  XcpHw_ErrorMsg("SetThreadAffinityMask()", GetLastError());
178  }
179 #else
180  /* Linux only (i.e. no BSD) ??? */
181  int res;
182  cpu_set_t cpuset;
183 
184  CPU_ZERO(&cpuset);
185  CPU_SET(0, &cpuset);
186 
187  res = pthread_setaffinity_np(thrd, sizeof(cpu_set_t), &cpuset);
188  if (res != 0) {
189  XcpHw_ErrorMsg("pthread_setaffinity_np()", errno);
190  }
191 
192  res = pthread_getaffinity_np(thrd, sizeof(cpu_set_t), &cpuset);
193  if (res != 0) {
194  XcpHw_ErrorMsg("pthread_getaffinity_np()", errno);
195  }
196 #endif
197 }