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 __linux__
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>
35void 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 ****************************************/
48EbHandle 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 __linux__
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 ****************************************/
110EbErrorType 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 __linux__
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 ****************************************/
139EbErrorType 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 __linux__
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 ****************************************/
157EbErrorType 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 __linux__
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 ***************************************/
176EbHandle 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 __linux__
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 ***************************************/
203EbErrorType 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 __linux__
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 ***************************************/
224EbErrorType 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 __linux__
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 ***************************************/
241EbErrorType 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 __linux__
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 ***************************************/
258EbHandle 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 __linux__
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 ***************************************/
285EbErrorType 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 __linux__
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 ***************************************/
302EbErrorType 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 __linux__
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 ***************************************/
319EbErrorType 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 __linux__
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 ***************************************/
338EbErrorType 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 __linux__
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