1/******************************************************************************
2*
3* Copyright (C) 2012 Ittiam Systems Pvt Ltd, Bangalore
4*
5* Licensed under the Apache License, Version 2.0 (the "License");
6* you may not use this file except in compliance with the License.
7* You may obtain a copy of the License at:
8*
9* http://www.apache.org/licenses/LICENSE-2.0
10*
11* Unless required by applicable law or agreed to in writing, software
12* distributed under the License is distributed on an "AS IS" BASIS,
13* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14* See the License for the specific language governing permissions and
15* limitations under the License.
16*
17******************************************************************************/
18/*****************************************************************************/
19/*                                                                           */
20/*  File Name         : ithread.c                                            */
21/*                                                                           */
22/*  Description       : Contains abstraction for threads, mutex and semaphores*/
23/*                                                                           */
24/*  List of Functions :                                                      */
25/*                                                                           */
26/*  Issues / Problems : None                                                 */
27/*                                                                           */
28/*  Revision History  :                                                      */
29/*                                                                           */
30/*         DD MM YYYY   Author(s)       Changes                              */
31/*         07 09 2012   Harish          Initial Version                      */
32/*****************************************************************************/
33/*****************************************************************************/
34/* File Includes                                                             */
35/*****************************************************************************/
36#include <string.h>
37#include "ihevc_typedefs.h"
38#include "ithread.h"
39#include <sys/types.h>
40
41#ifndef X86_MSVC
42//#define PTHREAD_AFFINITY
43//#define SYSCALL_AFFINITY
44
45#ifdef PTHREAD_AFFINITY
46#define _GNU_SOURCE
47#define __USE_GNU
48#endif
49
50#include <pthread.h>
51#include <sched.h>
52#include <semaphore.h>
53#include <unistd.h>
54
55
56#endif
57
58
59
60
61#ifdef X86_MSVC
62
63#include <windows.h>
64#define SEM_MAX_COUNT       100
65#define SEM_INCREMENT_COUNT 1
66
67UWORD32 ithread_get_handle_size(void)
68{
69    return (sizeof(HANDLE));
70}
71
72UWORD32 ithread_get_mutex_lock_size(void)
73{
74    return (sizeof(HANDLE));
75}
76
77WORD32 ithread_create(void *thread_handle, void *attribute, void *strt, void *argument)
78{
79    HANDLE *ppv_thread_handle;
80    HANDLE thread_handle_value;
81
82    if(0 == thread_handle)
83        return -1;
84
85    ppv_thread_handle = (HANDLE *)thread_handle;
86    thread_handle_value = (void *)CreateThread
87                    (NULL,                              /* Attributes      */
88                     1024 * 128,                        /* Stack size      */
89                     (LPTHREAD_START_ROUTINE)strt,      /* Thread function */
90                     argument,                          /* Parameters      */
91                     0,                                 /* Creation flags  */
92                     NULL);                             /* Thread ID       */
93    *ppv_thread_handle = (HANDLE)thread_handle_value;
94
95    return 0;
96}
97
98WORD32 ithread_join(void *thread_handle, void **val_ptr)
99{
100    HANDLE *ppv_thread_handle;
101    HANDLE thread_handle_value;
102
103    if(0 == thread_handle)
104        return -1;
105
106    ppv_thread_handle = (HANDLE *)thread_handle;
107    thread_handle_value = *ppv_thread_handle;
108
109    if(WAIT_OBJECT_0 == WaitForSingleObject(thread_handle_value, INFINITE))
110    {
111        CloseHandle(thread_handle_value);
112    }
113
114    return 0;
115}
116
117void ithread_exit(void *thread_handle)
118{
119    HANDLE *ppv_thread_handle;
120    HANDLE thread_handle_value;
121    DWORD thread_exit_code;
122
123    if(0 == thread_handle)
124        return;
125
126    ppv_thread_handle = (HANDLE *)thread_handle;
127    thread_handle_value = *ppv_thread_handle;
128    /* Get exit code for thread. If the return value is 0, means thread is busy */
129    if(0 != GetExitCodeThread(thread_handle_value, &thread_exit_code))
130    {
131        TerminateThread(thread_handle_value, thread_exit_code);
132    }
133
134    return;
135}
136
137WORD32 ithread_get_mutex_struct_size(void)
138{
139    return (sizeof(HANDLE));
140}
141
142WORD32 ithread_mutex_init(void *mutex)
143{
144    HANDLE *ppv_mutex_handle;
145    HANDLE mutex_handle_value;
146
147    if(0 == mutex)
148        return -1;
149
150    ppv_mutex_handle = (HANDLE *)mutex;
151    mutex_handle_value = CreateSemaphore(NULL, 1, 1, NULL);
152    *ppv_mutex_handle = mutex_handle_value;
153    return 0;
154}
155
156WORD32 ithread_mutex_destroy(void *mutex)
157{
158    HANDLE *ppv_mutex_handle;
159    HANDLE mutex_handle_value;
160
161    if(0 == mutex)
162        return -1;
163
164    ppv_mutex_handle = (HANDLE *)mutex;
165    mutex_handle_value = *ppv_mutex_handle;
166    CloseHandle(mutex_handle_value);
167    return 0;
168}
169
170WORD32 ithread_mutex_lock(void *mutex)
171{
172    HANDLE *ppv_mutex_handle;
173    HANDLE mutex_handle_value;
174    DWORD  result = 0;
175
176    if(0 == mutex)
177        return -1;
178
179    ppv_mutex_handle = (HANDLE *)mutex;
180    mutex_handle_value = *ppv_mutex_handle;
181    result = WaitForSingleObject(mutex_handle_value, INFINITE);
182
183    if(WAIT_OBJECT_0 == result)
184        return 0;
185
186    return 1;
187
188}
189
190WORD32 ithread_mutex_unlock(void *mutex)
191{
192    HANDLE *ppv_mutex_handle;
193    HANDLE mutex_handle_value;
194    DWORD  result = 0;
195
196    if(0 == mutex)
197        return -1;
198
199    ppv_mutex_handle = (HANDLE *)mutex;
200    mutex_handle_value = *ppv_mutex_handle;
201    result = ReleaseSemaphore(mutex_handle_value, 1, NULL);
202
203    if(0 == result)
204        return -1;
205
206    return 0;
207}
208
209void ithread_yield(void) { }
210
211void ithread_usleep(UWORD32 u4_time_us)
212{
213    UWORD32 u4_time_ms = u4_time_us / 1000;
214    Sleep(u4_time_ms);
215}
216
217void ithread_msleep(UWORD32 u4_time_ms)
218{
219    Sleep(u4_time_ms);
220}
221
222
223void ithread_sleep(UWORD32 u4_time)
224{
225    UWORD32 u4_time_ms = u4_time * 1000;
226    Sleep(u4_time_ms);
227}
228
229UWORD32 ithread_get_sem_struct_size(void)
230{
231    return (sizeof(HANDLE));
232}
233
234WORD32 ithread_sem_init(void *sem, WORD32 pshared, UWORD32 value)
235{
236    HANDLE *sem_handle = (HANDLE *)sem;
237    HANDLE sem_handle_value;
238
239    if(0 == sem)
240        return -1;
241
242    sem_handle_value = CreateSemaphore(NULL,  /* Security Attribute*/
243                                       value,  /* Initial count     */
244                                       SEM_MAX_COUNT, /* Max value         */
245                                       NULL);        /* Name, not used    */
246    *sem_handle = sem_handle_value;
247    return 0;
248}
249
250WORD32 ithread_sem_post(void *sem)
251{
252    HANDLE *sem_handle = (HANDLE *)sem;
253    HANDLE sem_handle_value;
254
255    if(0 == sem)
256        return -1;
257
258    sem_handle_value = *sem_handle;
259
260    /* Post on Semaphore by releasing the lock on mutex */
261    if(ReleaseSemaphore(sem_handle_value, SEM_INCREMENT_COUNT, NULL))
262        return 0;
263
264    return -1;
265}
266
267WORD32 ithread_sem_wait(void *sem)
268{
269    DWORD          result = 0;
270    HANDLE *sem_handle = (HANDLE *)sem;
271    HANDLE sem_handle_value;
272
273    if(0 == sem)
274        return -1;
275
276    sem_handle_value = *sem_handle;
277
278    /* Wait on Semaphore object infinitly */
279    result = WaitForSingleObject(sem_handle_value, INFINITE);
280
281    /* If lock on semaphore is acquired, return SUCCESS */
282    if(WAIT_OBJECT_0 == result)
283        return 0;
284
285    /* If call timeouts, return FAILURE */
286    if(WAIT_TIMEOUT == result)
287        return -1;
288
289    return 0;
290}
291
292WORD32 ithread_sem_destroy(void *sem)
293{
294    HANDLE *sem_handle = (HANDLE *)sem;
295    HANDLE sem_handle_value;
296
297    if(0 == sem)
298        return -1;
299
300    sem_handle_value = *sem_handle;
301
302    if(FALSE == CloseHandle(sem_handle_value))
303    {
304        return -1;
305    }
306    return 0;
307}
308
309WORD32 ithread_set_affinity(WORD32 core_id)
310{
311    return 1;
312}
313
314#else
315UWORD32 ithread_get_handle_size(void)
316{
317    return sizeof(pthread_t);
318}
319
320UWORD32 ithread_get_mutex_lock_size(void)
321{
322    return sizeof(pthread_mutex_t);
323}
324
325
326WORD32 ithread_create(void *thread_handle, void *attribute, void *strt, void *argument)
327{
328    return pthread_create((pthread_t *)thread_handle, attribute, (void * (*)(void *))strt, argument);
329}
330
331WORD32 ithread_join(void *thread_handle, void **val_ptr)
332{
333    pthread_t *pthread_handle   = (pthread_t *)thread_handle;
334    return pthread_join(*pthread_handle, val_ptr);
335}
336
337void ithread_exit(void *val_ptr)
338{
339    return pthread_exit(val_ptr);
340}
341
342WORD32 ithread_get_mutex_struct_size(void)
343{
344    return (sizeof(pthread_mutex_t));
345}
346WORD32 ithread_mutex_init(void *mutex)
347{
348    return pthread_mutex_init((pthread_mutex_t *)mutex, NULL);
349}
350
351WORD32 ithread_mutex_destroy(void *mutex)
352{
353    return pthread_mutex_destroy((pthread_mutex_t *)mutex);
354}
355
356WORD32 ithread_mutex_lock(void *mutex)
357{
358    return pthread_mutex_lock((pthread_mutex_t *)mutex);
359}
360
361WORD32 ithread_mutex_unlock(void *mutex)
362{
363    return pthread_mutex_unlock((pthread_mutex_t *)mutex);
364}
365
366void ithread_yield(void)
367{
368    sched_yield();
369}
370
371void ithread_sleep(UWORD32 u4_time)
372{
373    usleep(u4_time * 1000 * 1000);
374}
375
376void ithread_msleep(UWORD32 u4_time_ms)
377{
378    usleep(u4_time_ms * 1000);
379}
380
381void ithread_usleep(UWORD32 u4_time_us)
382{
383    usleep(u4_time_us);
384}
385
386UWORD32 ithread_get_sem_struct_size(void)
387{
388    return (sizeof(sem_t));
389}
390
391
392WORD32 ithread_sem_init(void *sem, WORD32 pshared, UWORD32 value)
393{
394    return sem_init((sem_t *)sem, pshared, value);
395}
396
397WORD32 ithread_sem_post(void *sem)
398{
399    return sem_post((sem_t *)sem);
400}
401
402
403WORD32 ithread_sem_wait(void *sem)
404{
405    return sem_wait((sem_t *)sem);
406}
407
408
409WORD32 ithread_sem_destroy(void *sem)
410{
411    return sem_destroy((sem_t *)sem);
412}
413
414
415WORD32 ithread_set_affinity(WORD32 core_id)
416{
417
418#ifdef PTHREAD_AFFINITY
419    cpu_set_t cpuset;
420    int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
421    pthread_t cur_thread = pthread_self();
422
423    if(core_id >= num_cores)
424        return -1;
425
426    CPU_ZERO(&cpuset);
427    CPU_SET(core_id, &cpuset);
428
429    return pthread_setaffinity_np(cur_thread, sizeof(cpu_set_t), &cpuset);
430
431#elif SYSCALL_AFFINITY
432    WORD32 i4_sys_res;
433
434    pid_t pid = gettid();
435
436
437    i4_sys_res = syscall(__NR_sched_setaffinity, pid, sizeof(i4_mask), &i4_mask);
438    if(i4_sys_res)
439    {
440        //WORD32 err;
441        //err = errno;
442        //perror("Error in setaffinity syscall PERROR : ");
443        //LOG_ERROR("Error in the syscall setaffinity: mask=0x%x err=0x%x", i4_mask, i4_sys_res);
444        return -1;
445    }
446#endif
447
448    return core_id;
449
450}
451#endif
452