1 /*
2 * Copyright(c) 2019 Intel Corporation
3 * SPDX - License - Identifier: BSD - 2 - Clause - Patent
4 */
5 
6 // Summary:
7 // EbThreads contains wrappers functions that hide
8 // platform specific objects such as threads, semaphores,
9 // and mutexs.  The goal is to eliminiate platform #define
10 // in the code.
11 
12 /****************************************
13  * Universal Includes
14  ****************************************/
15 #include <stdlib.h>
16 #include "EbDefinitions.h"
17 #include "EbThreads.h"
18 
19 /****************************************
20  * Win32 Includes
21  ****************************************/
22 #ifdef _WIN32
23 #include <windows.h>
24 #elif __unix__
25 #include <pthread.h>
26 #include <semaphore.h>
27 #include <time.h>
28 #include <errno.h>
29 #else
30 #error OS/Platform not supported.
31 #endif // _WIN32
32 #if PRINTF_TIME
33 #ifdef _WIN32
34 #include <time.h>
printfTime(const char * fmt,...)35 void printfTime(const char *fmt, ...)
36 {
37     va_list args;
38     va_start(args, fmt);
39     SVT_LOG("  [%i ms]\t", ((int)clock()));
40     vprintf(fmt, args);
41     va_end(args);
42 }
43 #endif
44 #endif
45 /****************************************
46  * eb_vp9_create_thread
47  ****************************************/
eb_vp9_create_thread(void * thread_function (void *),void * thread_context)48 EbHandle eb_vp9_create_thread(
49     void *thread_function(void *),
50     void *thread_context)
51 {
52     EbHandle thread_handle = NULL;
53 
54 #ifdef _WIN32
55 
56     thread_handle = (EbHandle) CreateThread(
57                        NULL,                           // default security attributes
58                        0,                              // default stack size
59                        (LPTHREAD_START_ROUTINE) thread_function, // function to be tied to the new thread
60                        thread_context,                  // context to be tied to the new thread
61                        0,                              // thread active when created
62                        NULL);                          // new thread ID
63 
64 #elif __unix__
65 
66     pthread_attr_t attr;
67     struct sched_param param = {
68         .sched_priority = 99
69     };
70     pthread_attr_init(&attr);
71     pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
72     pthread_attr_setschedparam(&attr, &param);
73 
74     pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
75 
76     thread_handle = (pthread_t*) malloc(sizeof(pthread_t));
77     if (thread_handle != NULL) {
78         int ret = pthread_create(
79             (pthread_t*)thread_handle,      // Thread handle
80             &attr,                       // attributes
81             thread_function,                 // function to be run by new thread
82             thread_context);
83 
84         if (ret != 0) {
85             if (ret == EPERM) {
86 
87                 pthread_cancel(*((pthread_t*)thread_handle));
88                 free(thread_handle);
89 
90                 thread_handle = (pthread_t*)malloc(sizeof(pthread_t));
91                 if (thread_handle != NULL) {
92                     pthread_create(
93                         (pthread_t*)thread_handle,      // Thread handle
94                         (const pthread_attr_t*)EB_NULL,                        // attributes
95                         thread_function,                 // function to be run by new thread
96                         thread_context);
97                 }
98             }
99         }
100     }
101     pthread_attr_destroy(&attr);
102 #endif // _WIN32
103 
104     return thread_handle;
105 }
106 
107 /****************************************
108  * eb_start_thread
109  ****************************************/
eb_start_thread(EbHandle thread_handle)110 EbErrorType eb_start_thread(
111     EbHandle thread_handle)
112 {
113     EbErrorType error_return = EB_ErrorNone;
114 
115     /* Note JMJ 9/6/2011
116         The thread Pause/Resume functionality is being removed.  The main reason is that
117         POSIX Threads (aka pthreads) does not support this functionality.  The destructor
118         and deinit code is safe as along as when EbDestropyThread is called on a thread,
119         the thread is immediately destroyed and its stack cleared.
120 
121         The Encoder Start/Stop functionality, which previously used the thread Pause/Resume
122         functions could be implemented with mutex checks either at the head of the pipeline,
123         or throughout the code if a more responsive Pause is needed.
124     */
125 
126 #ifdef _WIN32
127     //error_return = ResumeThread((HANDLE) thread_handle) ? EB_ErrorThreadUnresponsive : EB_ErrorNone;
128 #elif __unix__
129 #endif // _WIN32
130 
131     error_return = (thread_handle) ? EB_ErrorNone : EB_ErrorNullThread;
132 
133     return error_return;
134 }
135 
136 /****************************************
137  * eb_stop_thread
138  ****************************************/
eb_stop_thread(EbHandle thread_handle)139 EbErrorType eb_stop_thread(
140     EbHandle thread_handle)
141 {
142     EbErrorType error_return = EB_ErrorNone;
143 
144 #ifdef _WIN32
145     //error_return = SuspendThread((HANDLE) thread_handle) ? EB_ErrorThreadUnresponsive : EB_ErrorNone;
146 #elif __unix__
147 #endif // _WIN32
148 
149     error_return = (thread_handle) ? EB_ErrorNone : EB_ErrorNullThread;
150 
151     return error_return;
152 }
153 
154 /****************************************
155  * eb_vp9_destroy_thread
156  ****************************************/
eb_vp9_destroy_thread(EbHandle thread_handle)157 EbErrorType eb_vp9_destroy_thread(
158     EbHandle thread_handle)
159 {
160     EbErrorType error_return = EB_ErrorNone;
161 
162 #ifdef _WIN32
163     error_return = TerminateThread((HANDLE) thread_handle, 0) ? EB_ErrorDestroyThreadFailed : EB_ErrorNone;
164 #elif __unix__
165     error_return = pthread_cancel(*((pthread_t*) thread_handle)) ? EB_ErrorDestroyThreadFailed : EB_ErrorNone;
166     pthread_join(*((pthread_t*) thread_handle), NULL);
167     free(thread_handle);
168 #endif // _WIN32
169 
170     return error_return;
171 }
172 
173 /***************************************
174  * eb_vp9_create_semaphore
175  ***************************************/
eb_vp9_create_semaphore(uint32_t initial_count,uint32_t max_count)176 EbHandle eb_vp9_create_semaphore(
177     uint32_t initial_count,
178     uint32_t max_count)
179 {
180     EbHandle semaphore_handle = NULL;
181     (void) max_count;
182 
183 #ifdef _WIN32
184     semaphore_handle = (EbHandle) CreateSemaphore(
185                           NULL,                           // default security attributes
186                           initial_count,                   // initial semaphore count
187                           max_count,                       // maximum semaphore count
188                           NULL);                          // semaphore is not named
189 #elif __unix__
190     semaphore_handle = (sem_t*) malloc(sizeof(sem_t));
191     sem_init(
192         (sem_t*) semaphore_handle,       // semaphore handle
193         0,                              // shared semaphore (not local)
194         initial_count);                  // initial count
195 #endif // _WIN32
196 
197     return semaphore_handle;
198 }
199 
200 /***************************************
201  * eb_vp9_post_semaphore
202  ***************************************/
eb_vp9_post_semaphore(EbHandle semaphore_handle)203 EbErrorType eb_vp9_post_semaphore(
204     EbHandle semaphore_handle)
205 {
206     EbErrorType return_error = EB_ErrorNone;
207 
208 #ifdef _WIN32
209     return_error = ReleaseSemaphore(
210                        semaphore_handle,    // semaphore handle
211                        1,                  // amount to increment the semaphore
212                        NULL)               // pointer to previous count (optional)
213                    ? EB_ErrorSemaphoreUnresponsive : EB_ErrorNone;
214 #elif __unix__
215     return_error = sem_post((sem_t*) semaphore_handle) ? EB_ErrorSemaphoreUnresponsive : EB_ErrorNone;
216 #endif // _WIN32
217 
218     return return_error;
219 }
220 
221 /***************************************
222  * eb_vp9_block_on_semaphore
223  ***************************************/
eb_vp9_block_on_semaphore(EbHandle semaphore_handle)224 EbErrorType eb_vp9_block_on_semaphore(
225     EbHandle semaphore_handle)
226 {
227     EbErrorType return_error = EB_ErrorNone;
228 
229 #ifdef _WIN32
230     return_error = WaitForSingleObject((HANDLE) semaphore_handle, INFINITE) ? EB_ErrorSemaphoreUnresponsive : EB_ErrorNone;
231 #elif __unix__
232     return_error = sem_wait((sem_t*) semaphore_handle) ? EB_ErrorSemaphoreUnresponsive : EB_ErrorNone;
233 #endif // _WIN32
234 
235     return return_error;
236 }
237 
238 /***************************************
239  * eb_vp9_destroy_semaphore
240  ***************************************/
eb_vp9_destroy_semaphore(EbHandle semaphore_handle)241 EbErrorType eb_vp9_destroy_semaphore(
242     EbHandle semaphore_handle)
243 {
244     EbErrorType return_error = EB_ErrorNone;
245 
246 #ifdef _WIN32
247     return_error = CloseHandle((HANDLE) semaphore_handle) ? EB_ErrorDestroySemaphoreFailed : EB_ErrorNone;
248 #elif __unix__
249     return_error = sem_destroy((sem_t*) semaphore_handle) ? EB_ErrorDestroySemaphoreFailed : EB_ErrorNone;
250     free(semaphore_handle);
251 #endif // _WIN32
252 
253     return return_error;
254 }
255 /***************************************
256  * eb_vp9_create_mutex
257  ***************************************/
eb_vp9_create_mutex(void)258 EbHandle eb_vp9_create_mutex(
259     void)
260 {
261     EbHandle mutex_handle = NULL;
262 
263 #ifdef _WIN32
264     mutex_handle = (EbHandle) CreateMutex(
265                       NULL,                   // default security attributes
266                       FALSE,                  // FALSE := not initially owned
267                       NULL);                  // mutex is not named
268 
269 #elif __unix__
270 
271     mutex_handle = (EbHandle) malloc(sizeof(pthread_mutex_t));
272     if (mutex_handle != NULL) {
273         pthread_mutex_init(
274             (pthread_mutex_t*)mutex_handle,
275             NULL);                  // default attributes
276     }
277 #endif // _WIN32
278 
279     return mutex_handle;
280 }
281 
282 /***************************************
283  * EbPostMutex
284  ***************************************/
eb_vp9_release_mutex(EbHandle mutex_handle)285 EbErrorType eb_vp9_release_mutex(
286     EbHandle mutex_handle)
287 {
288     EbErrorType return_error = EB_ErrorNone;
289 
290 #ifdef _WIN32
291     return_error = ReleaseMutex((HANDLE) mutex_handle)? EB_ErrorCreateMutexFailed : EB_ErrorNone;
292 #elif __unix__
293     return_error = pthread_mutex_unlock((pthread_mutex_t*) mutex_handle) ? EB_ErrorCreateMutexFailed : EB_ErrorNone;
294 #endif // _WIN32
295 
296     return return_error;
297 }
298 
299 /***************************************
300  * eb_vp9_block_on_mutex
301  ***************************************/
eb_vp9_block_on_mutex(EbHandle mutex_handle)302 EbErrorType eb_vp9_block_on_mutex(
303     EbHandle mutex_handle)
304 {
305     EbErrorType return_error = EB_ErrorNone;
306 
307 #ifdef _WIN32
308     return_error = WaitForSingleObject((HANDLE) mutex_handle, INFINITE) ? EB_ErrorMutexUnresponsive : EB_ErrorNone;
309 #elif __unix__
310     return_error = pthread_mutex_lock((pthread_mutex_t*) mutex_handle) ? EB_ErrorMutexUnresponsive : EB_ErrorNone;
311 #endif // _WIN32
312 
313     return return_error;
314 }
315 
316 /***************************************
317  * eb_vp9_block_on_mutex_timeout
318  ***************************************/
eb_vp9_block_on_mutex_timeout(EbHandle mutex_handle,uint32_t timeout)319 EbErrorType eb_vp9_block_on_mutex_timeout(
320     EbHandle mutex_handle,
321     uint32_t    timeout)
322 {
323     EbErrorType return_error = EB_ErrorNone;
324 
325 #ifdef _WIN32
326     WaitForSingleObject((HANDLE) mutex_handle, timeout);
327 #elif __unix__
328     return_error = pthread_mutex_lock((pthread_mutex_t*) mutex_handle) ? EB_ErrorMutexUnresponsive : EB_ErrorNone;
329     (void) timeout;
330 #endif // _WIN32
331 
332     return return_error;
333 }
334 
335 /***************************************
336  * eb_vp9_destroy_mutex
337  ***************************************/
eb_vp9_destroy_mutex(EbHandle mutex_handle)338 EbErrorType eb_vp9_destroy_mutex(
339     EbHandle mutex_handle)
340 {
341     EbErrorType return_error = EB_ErrorNone;
342 
343 #ifdef _WIN32
344     return_error = CloseHandle((HANDLE) mutex_handle) ? EB_ErrorDestroyMutexFailed : EB_ErrorNone;
345 #elif __unix__
346     return_error = pthread_mutex_destroy((pthread_mutex_t*) mutex_handle) ? EB_ErrorDestroyMutexFailed : EB_ErrorNone;
347     free(mutex_handle);
348 #endif // _WIN32
349 
350     return return_error;
351 }
352