1 /**
2 * @file lv_windows.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9
10 #include "lv_os.h"
11
12 #if LV_USE_OS == LV_OS_WINDOWS
13
14 #include <process.h>
15
16 /*********************
17 * DEFINES
18 *********************/
19
20 /**********************
21 * TYPEDEFS
22 **********************/
23
24 typedef struct {
25 void (*callback)(void *);
26 void * user_data;
27 } lv_thread_init_data_t;
28
29 /**********************
30 * STATIC PROTOTYPES
31 **********************/
32
33 static unsigned __stdcall thread_start_routine(void * parameter);
34
35 /**********************
36 * STATIC VARIABLES
37 **********************/
38
39 /**********************
40 * MACROS
41 **********************/
42
43 /**********************
44 * GLOBAL FUNCTIONS
45 **********************/
46
lv_thread_init(lv_thread_t * thread,const char * const name,lv_thread_prio_t prio,void (* callback)(void *),size_t stack_size,void * user_data)47 lv_result_t lv_thread_init(
48 lv_thread_t * thread,
49 const char * const name,
50 lv_thread_prio_t prio,
51 void (*callback)(void *),
52 size_t stack_size,
53 void * user_data)
54 {
55 LV_UNUSED(name);
56 if(!thread) {
57 return LV_RESULT_INVALID;
58 }
59
60 static const int prio_map[] = {
61 [LV_THREAD_PRIO_LOWEST] = THREAD_PRIORITY_LOWEST,
62 [LV_THREAD_PRIO_LOW] = THREAD_PRIORITY_BELOW_NORMAL,
63 [LV_THREAD_PRIO_MID] = THREAD_PRIORITY_NORMAL,
64 [LV_THREAD_PRIO_HIGH] = THREAD_PRIORITY_ABOVE_NORMAL,
65 [LV_THREAD_PRIO_HIGHEST] = THREAD_PRIORITY_HIGHEST,
66 };
67
68 lv_thread_init_data_t * init_data =
69 (lv_thread_init_data_t *)(malloc(
70 sizeof(lv_thread_init_data_t)));
71 if(!init_data) {
72 return LV_RESULT_INVALID;
73 }
74 init_data->callback = callback;
75 init_data->user_data = user_data;
76
77 /*
78 Reference: https://learn.microsoft.com/en-us/windows/win32/api
79 /processthreadsapi/nf-processthreadsapi-createthread
80
81 A thread in an executable that calls the C run-time library (CRT) should
82 use the _beginthreadex and _endthreadex functions for thread management
83 rather than CreateThread and ExitThread; this requires the use of the
84 multithreaded version of the CRT. If a thread created using CreateThread
85 calls the CRT, the CRT may terminate the process in low-memory conditions.
86 */
87 *thread = (HANDLE)(_beginthreadex(
88 NULL,
89 (unsigned)(stack_size),
90 thread_start_routine,
91 init_data,
92 0,
93 NULL));
94 if(!*thread) {
95 return LV_RESULT_INVALID;
96 }
97
98 /*
99 Try to set the thread priority. (Not mandatory for creating a new thread.)
100 */
101 SetThreadPriority(*thread, prio_map[prio]);
102
103 return LV_RESULT_OK;
104 }
105
lv_thread_delete(lv_thread_t * thread)106 lv_result_t lv_thread_delete(lv_thread_t * thread)
107 {
108 lv_result_t result = LV_RESULT_OK;
109
110 if(!TerminateThread(thread, 0)) {
111 result = LV_RESULT_INVALID;
112 }
113
114 CloseHandle(thread);
115
116 return result;
117 }
118
lv_mutex_init(lv_mutex_t * mutex)119 lv_result_t lv_mutex_init(lv_mutex_t * mutex)
120 {
121 InitializeCriticalSection(mutex);
122 return LV_RESULT_OK;
123 }
124
lv_mutex_lock(lv_mutex_t * mutex)125 lv_result_t lv_mutex_lock(lv_mutex_t * mutex)
126 {
127 EnterCriticalSection(mutex);
128 return LV_RESULT_OK;
129 }
130
lv_mutex_lock_isr(lv_mutex_t * mutex)131 lv_result_t lv_mutex_lock_isr(lv_mutex_t * mutex)
132 {
133 EnterCriticalSection(mutex);
134 return LV_RESULT_OK;
135 }
136
lv_mutex_unlock(lv_mutex_t * mutex)137 lv_result_t lv_mutex_unlock(lv_mutex_t * mutex)
138 {
139 LeaveCriticalSection(mutex);
140 return LV_RESULT_OK;
141 }
142
lv_mutex_delete(lv_mutex_t * mutex)143 lv_result_t lv_mutex_delete(lv_mutex_t * mutex)
144 {
145 DeleteCriticalSection(mutex);
146 return LV_RESULT_OK;
147 }
148
lv_thread_sync_init(lv_thread_sync_t * sync)149 lv_result_t lv_thread_sync_init(lv_thread_sync_t * sync)
150 {
151 if(!sync) {
152 return LV_RESULT_INVALID;
153 }
154
155 InitializeCriticalSection(&sync->cs);
156 InitializeConditionVariable(&sync->cv);
157 sync->v = false;
158
159 return LV_RESULT_OK;
160 }
161
lv_thread_sync_wait(lv_thread_sync_t * sync)162 lv_result_t lv_thread_sync_wait(lv_thread_sync_t * sync)
163 {
164 if(!sync) {
165 return LV_RESULT_INVALID;
166 }
167
168 EnterCriticalSection(&sync->cs);
169 while(!sync->v) {
170 SleepConditionVariableCS(&sync->cv, &sync->cs, INFINITE);
171 }
172 sync->v = false;
173 LeaveCriticalSection(&sync->cs);
174
175 return LV_RESULT_OK;
176 }
177
lv_thread_sync_signal(lv_thread_sync_t * sync)178 lv_result_t lv_thread_sync_signal(lv_thread_sync_t * sync)
179 {
180 if(!sync) {
181 return LV_RESULT_INVALID;
182 }
183
184 EnterCriticalSection(&sync->cs);
185 sync->v = true;
186 WakeConditionVariable(&sync->cv);
187 LeaveCriticalSection(&sync->cs);
188
189 return LV_RESULT_OK;
190 }
191
lv_thread_sync_delete(lv_thread_sync_t * sync)192 lv_result_t lv_thread_sync_delete(lv_thread_sync_t * sync)
193 {
194 if(!sync) {
195 return LV_RESULT_INVALID;
196 }
197
198 DeleteCriticalSection(&sync->cs);
199
200 return LV_RESULT_OK;
201 }
202
lv_thread_sync_signal_isr(lv_thread_sync_t * sync)203 lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * sync)
204 {
205 LV_UNUSED(sync);
206 return LV_RESULT_INVALID;
207 }
208
209 /**********************
210 * STATIC FUNCTIONS
211 **********************/
212
thread_start_routine(void * parameter)213 static unsigned __stdcall thread_start_routine(void * parameter)
214 {
215 lv_thread_init_data_t * init_data = (lv_thread_init_data_t *)(parameter);
216 if(init_data) {
217 init_data->callback(init_data->user_data);
218 free(init_data);
219 }
220
221 return 0;
222 }
223
224 #endif /*LV_USE_OS == LV_OS_WINDOWS*/
225