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