LCOV - code coverage report
Current view: top level - utils - os_thread.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 159 202 78.7 %
Date: 2021-04-29 23:48:07 Functions: 22 23 95.7 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / common tools sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : #ifndef GPAC_DISABLE_CORE_TOOLS
      27             : 
      28             : #ifdef GPAC_CONFIG_ANDROID
      29             : #include <jni.h>
      30             : #endif
      31             : 
      32             : #include <gpac/thread.h>
      33             : 
      34             : #if defined(WIN32) || defined(_WIN32_WCE)
      35             : 
      36             : /*win32 threads*/
      37             : #include <windows.h>
      38             : typedef HANDLE TH_HANDLE;
      39             : 
      40             : #else
      41             : /*pthreads*/
      42             : #include <sched.h>
      43             : #include <pthread.h>
      44             : #include <semaphore.h>
      45             : #include <errno.h>
      46             : typedef pthread_t TH_HANDLE ;
      47             : 
      48             : #endif
      49             : 
      50             : 
      51             : 
      52             : /*********************************************************************
      53             :                                                 OS-Specific Thread Object
      54             : **********************************************************************/
      55             : struct __tag_thread
      56             : {
      57             : 
      58             :         u32 status;
      59             :         TH_HANDLE threadH;
      60             :         u32 stackSize;
      61             :         /* the thread procedure */
      62             :         u32 (*Run)(void *param);
      63             :         void *args;
      64             :         /* lock for signal */
      65             :         GF_Semaphore *_signal;
      66             : #ifndef GPAC_DISABLE_LOG
      67             :         u32 id;
      68             :         char *log_name;
      69             : #endif
      70             : #ifdef GPAC_CONFIG_ANDROID
      71             :         u32 (*RunBeforeExit)(void *param);
      72             : #endif
      73             : };
      74             : 
      75             : 
      76             : #ifndef GPAC_DISABLE_LOG
      77             : #include <gpac/list.h>
      78             : static GF_List *thread_bank = NULL;
      79             : 
      80         225 : static void log_add_thread(GF_Thread *t)
      81             : {
      82         225 :         if (!thread_bank) thread_bank = gf_list_new();
      83         225 :         gf_list_add(thread_bank, t);
      84         225 : }
      85         223 : static void log_del_thread(GF_Thread *t)
      86             : {
      87         223 :         gf_list_del_item(thread_bank, t);
      88         223 :         if (!gf_list_count(thread_bank)) {
      89          97 :                 gf_list_del(thread_bank);
      90          97 :                 thread_bank = NULL;
      91             :         }
      92         223 : }
      93       48121 : static const char *log_th_name(u32 id)
      94             : {
      95             :         u32 i, count;
      96             : 
      97       48121 :         if (!id) id = gf_th_id();
      98       48121 :         count = gf_list_count(thread_bank);
      99      126780 :         for (i=0; i<count; i++) {
     100       97471 :                 GF_Thread *t = (GF_Thread*)gf_list_get(thread_bank, i);
     101       97471 :                 if (t->id == id) return t->log_name;
     102             :         }
     103             :         return "Main Process";
     104             : }
     105             : 
     106             : #endif
     107             : 
     108             : 
     109             : GF_EXPORT
     110         225 : GF_Thread *gf_th_new(const char *name)
     111             : {
     112         225 :         GF_Thread *tmp = (GF_Thread*)gf_malloc(sizeof(GF_Thread));
     113             :         memset(tmp, 0, sizeof(GF_Thread));
     114         225 :         tmp->status = GF_THREAD_STATUS_STOP;
     115             : 
     116             : #ifndef GPAC_DISABLE_LOG
     117         225 :         if (name) {
     118         225 :                 tmp->log_name = gf_strdup(name);
     119             :         } else {
     120             :                 char szN[20];
     121             :                 sprintf(szN, "%p", (void*)tmp);
     122           0 :                 tmp->log_name = gf_strdup(szN);
     123             :         }
     124         225 :         log_add_thread(tmp);
     125             : #endif
     126         225 :         return tmp;
     127             : }
     128             : 
     129             : 
     130             : #ifdef GPAC_CONFIG_ANDROID
     131             : #include <pthread.h>
     132             : 
     133             : static pthread_key_t currentThreadInfoKey = 0;
     134             : 
     135             : /* Unique allocation of key */
     136             : static pthread_once_t currentThreadInfoKey_once = PTHREAD_ONCE_INIT;
     137             : 
     138             : GF_Err gf_register_before_exit_function(GF_Thread *t, u32 (*toRunBeforePthreadExit)(void *param) )
     139             : {
     140             :         if (!t)
     141             :                 return GF_BAD_PARAM;
     142             :         t->RunBeforeExit = toRunBeforePthreadExit;
     143             :         return GF_OK;
     144             : }
     145             : 
     146             : /* Unique key allocation */
     147             : static void currentThreadInfoKey_alloc()
     148             : {
     149             :         int err;
     150             :         /* We do not use any destructor */
     151             :         err = pthread_key_create(&currentThreadInfoKey, NULL);
     152             :         if (err) {
     153             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex] pthread_key_create() failed with error %d\n", err));
     154             :         }
     155             : }
     156             : 
     157             : GF_Thread * gf_th_current() {
     158             :         return pthread_getspecific(currentThreadInfoKey);
     159             : }
     160             : 
     161             : #endif /* GPAC_CONFIG_ANDROID */
     162             : 
     163             : 
     164             : #ifdef WIN32
     165             : DWORD WINAPI RunThread(void *ptr)
     166             : {
     167             :         DWORD ret = 0;
     168             : #else
     169         225 : void * RunThread(void *ptr)
     170             : {
     171             :         long int ret = 0;
     172             : #endif
     173             :         GF_Thread *t = (GF_Thread *)ptr;
     174             : 
     175             :         /* Signal the caller */
     176         225 :         if (! t->_signal) goto exit;
     177             : #ifdef GPAC_CONFIG_ANDROID
     178             :         if (pthread_once(&currentThreadInfoKey_once, &currentThreadInfoKey_alloc) || pthread_setspecific(currentThreadInfoKey, t))
     179             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex] Couldn't run thread %s, ID 0x%08x\n", t->log_name, t->id));
     180             : #endif /* GPAC_CONFIG_ANDROID */
     181         225 :         t->status = GF_THREAD_STATUS_RUN;
     182         225 :         gf_sema_notify(t->_signal, 1);
     183             : 
     184             : #ifndef GPAC_DISABLE_LOG
     185         225 :         t->id = gf_th_id();
     186         225 :         GF_LOG(GF_LOG_INFO, GF_LOG_MUTEX, ("[Thread %s] At %d Entering thread proc - thread ID 0x%08x\n", t->log_name, gf_sys_clock(), t->id));
     187             : #endif
     188             : 
     189             :         /* Each thread has its own seed */
     190         225 :         gf_rand_init(GF_FALSE);
     191             : 
     192             :         /* Run our thread */
     193         225 :         ret = t->Run(t->args);
     194             : 
     195         222 : exit:
     196             : #ifndef GPAC_DISABLE_LOG
     197         222 :         GF_LOG(GF_LOG_INFO, GF_LOG_MUTEX, ("[Thread %s] At %d Exiting thread proc, return code %d\n", t->log_name, gf_sys_clock(), ret));
     198             : #endif
     199         223 :         t->status = GF_THREAD_STATUS_DEAD;
     200         223 :         t->Run = NULL;
     201             : #ifdef WIN32
     202             :         if (!CloseHandle(t->threadH)) {
     203             :                 DWORD err = GetLastError();
     204             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Thread %s] Couldn't close handle when exiting thread proc, error code: %d\n", t->log_name, err));
     205             :         }
     206             :         t->threadH = NULL;
     207             :         return ret;
     208             : #else
     209             : 
     210             : #ifdef GPAC_CONFIG_ANDROID
     211             : #ifndef GPAC_DISABLE_LOG
     212             :         GF_LOG(GF_LOG_INFO, GF_LOG_MUTEX, ("[Thread %s] RunBeforeExit=%p\n", t->log_name, t->RunBeforeExit));
     213             : #endif
     214             :         if (t->RunBeforeExit)
     215             :                 t->RunBeforeExit(t->args);
     216             : #endif /* GPAC_CONFIG_ANDROID */
     217         223 :         pthread_exit((void *)0);
     218             :         return (void *)ret;
     219             : #endif
     220             : }
     221             : 
     222             : GF_EXPORT
     223         225 : GF_Err gf_th_run(GF_Thread *t, u32 (*Run)(void *param), void *param)
     224             : {
     225             : #ifdef WIN32
     226             :         DWORD id;
     227             : #else
     228             :         pthread_attr_t att;
     229             : #endif
     230         225 :         if (!t || t->Run || t->_signal) return GF_BAD_PARAM;
     231         225 :         t->Run = Run;
     232         225 :         t->args = param;
     233         225 :         t->_signal = gf_sema_new(1, 0);
     234             : 
     235         225 :         if (!t->_signal)
     236             :                 return GF_IO_ERR;
     237             : 
     238         225 :         GF_LOG(GF_LOG_INFO, GF_LOG_MUTEX, ("[Thread %s] Starting\n", t->log_name));
     239             : 
     240             : #ifdef WIN32
     241             :         t->threadH = CreateThread(NULL, t->stackSize, &(RunThread), (void *)t, 0, &id);
     242             :         if (t->threadH != NULL) {
     243             : #ifdef _MSC_VER
     244             :                 /*add thread name for the msvc debugger*/
     245             : #pragma pack(push,8)
     246             :                 typedef struct {
     247             :                         DWORD dwType;
     248             :                         LPCSTR szName;
     249             :                         DWORD dwThreadID;
     250             :                         DWORD dwFlags;
     251             :                 } THREADNAME_INFO;
     252             : #pragma pack(pop)
     253             :                 THREADNAME_INFO info;
     254             :                 info.dwType = 0x1000;
     255             :                 info.szName = t->log_name;
     256             :                 info.dwThreadID = id;
     257             :                 info.dwFlags = 0;
     258             :                 __try {
     259             :                         RaiseException(0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
     260             :                 } __except (EXCEPTION_CONTINUE_EXECUTION) {
     261             :                 }
     262             : #endif
     263             :         } else {
     264             : #else
     265         225 :         if ( pthread_attr_init(&att) != 0 ) return GF_IO_ERR;
     266         225 :         pthread_attr_setdetachstate(&att, PTHREAD_CREATE_JOINABLE);
     267         225 :         if ( pthread_create(&t->threadH, &att, RunThread, t) != 0 ) {
     268             : #endif
     269           0 :                 t->status = GF_THREAD_STATUS_DEAD;
     270           0 :                 return GF_IO_ERR;
     271             :         }
     272             : 
     273             :         /*wait for the child function to call us - do NOT return before, otherwise the thread status would
     274             :         be unknown*/
     275         225 :         gf_sema_wait(t->_signal);
     276         225 :         gf_sema_del(t->_signal);
     277         225 :         t->_signal = NULL;
     278         225 :         GF_LOG(GF_LOG_INFO, GF_LOG_MUTEX, ("[Thread %s] Started\n", t->log_name));
     279             :         return GF_OK;
     280             : }
     281             : 
     282             : 
     283             : /* Stops a thread. If Destroy is not 0, thread is destroyed DANGEROUS as no cleanup */
     284         223 : void Thread_Stop(GF_Thread *t, Bool Destroy)
     285             : {
     286         223 :         if (gf_th_status(t) == GF_THREAD_STATUS_RUN) {
     287             : #ifdef WIN32
     288             :                 if (Destroy) {
     289             :                         DWORD dw = 1;
     290             :                         BOOL ret = TerminateThread(t->threadH, dw);
     291             :                         if (!ret) {
     292             :                                 DWORD err = GetLastError();
     293             :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Thread %s] Couldn't stop thread ID 0x%08x, error code %d\n", t->log_name, t->id, err));
     294             :                         }
     295             :                         t->threadH = NULL;
     296             :                 } else {
     297             :                         WaitForSingleObject(t->threadH, INFINITE);
     298             :                 }
     299             : #else
     300           0 :                 if (Destroy) {
     301             : #if defined(GPAC_CONFIG_ANDROID) || defined(PTHREAD_HAS_NO_CANCEL)
     302             :                         if (pthread_kill(t->threadH, SIGQUIT))
     303             : #else
     304           0 :                         if (pthread_cancel(t->threadH))
     305             : #endif
     306           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Thread %s] Couldn't kill thread ID 0x%08x\n", t->log_name, t->id));
     307           0 :                         t->threadH = 0;
     308             :                 } else {
     309             :                         /*gracefully wait for Run to finish*/
     310           0 :                         if (pthread_join(t->threadH, NULL))
     311           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Thread %s] pthread_join() returned an error with thread ID 0x%08x\n", t->log_name, t->id));
     312             :                 }
     313             : #endif
     314             :         }
     315         223 :         t->status = GF_THREAD_STATUS_DEAD;
     316         223 : }
     317             : 
     318             : GF_EXPORT
     319           1 : void gf_th_stop(GF_Thread *t)
     320             : {
     321           1 :         if (t) Thread_Stop(t, GF_FALSE);
     322           1 : }
     323             : 
     324             : GF_EXPORT
     325         223 : void gf_th_del(GF_Thread *t)
     326             : {
     327         223 :         Thread_Stop(t, GF_FALSE);
     328             : #ifdef WIN32
     329             : //      if (t->threadH) CloseHandle(t->threadH);
     330             : #else
     331             :         /* It is necessary to free pthread handle */
     332         223 :         if (t->threadH)
     333         223 :                 pthread_detach(t->threadH);
     334         223 :         t->threadH = 0;
     335             : #endif
     336             : 
     337             : #ifndef GPAC_DISABLE_LOG
     338         223 :         gf_free(t->log_name);
     339         223 :         log_del_thread(t);
     340             : #endif
     341         223 :         gf_free(t);
     342         223 : }
     343             : 
     344             : GF_EXPORT
     345           0 : void gf_th_set_priority(GF_Thread *t, s32 priority)
     346             : {
     347             : #ifdef WIN32
     348             :         /*!! in WinCE, changin thread priority is extremely dangerous, it may freeze threads randomly !!*/
     349             : #ifndef _WIN32_WCE
     350             :         int _prio;
     351             :         BOOL ret;
     352             :         switch (priority) {
     353             :         case GF_THREAD_PRIORITY_IDLE:
     354             :                 _prio = THREAD_PRIORITY_IDLE;
     355             :                 break;
     356             :         case GF_THREAD_PRIORITY_LESS_IDLE:
     357             :                 _prio = THREAD_PRIORITY_IDLE;
     358             :                 break;
     359             :         case GF_THREAD_PRIORITY_LOWEST:
     360             :                 _prio = THREAD_PRIORITY_LOWEST;
     361             :                 break;
     362             :         case GF_THREAD_PRIORITY_LOW:
     363             :                 _prio = THREAD_PRIORITY_BELOW_NORMAL;
     364             :                 break;
     365             :         case GF_THREAD_PRIORITY_NORMAL:
     366             :                 _prio = THREAD_PRIORITY_NORMAL;
     367             :                 break;
     368             :         case GF_THREAD_PRIORITY_HIGH:
     369             :                 _prio = THREAD_PRIORITY_ABOVE_NORMAL;
     370             :                 break;
     371             :         case GF_THREAD_PRIORITY_HIGHEST:
     372             :                 _prio = THREAD_PRIORITY_HIGHEST;
     373             :                 break;
     374             :         default: /*GF_THREAD_PRIORITY_REALTIME -> GF_THREAD_PRIORITY_REALTIME_END*/
     375             :                 _prio = THREAD_PRIORITY_TIME_CRITICAL;
     376             :                 break;
     377             :         }
     378             :         ret = SetThreadPriority(t ? t->threadH : GetCurrentThread(), _prio);
     379             :         if (!ret) {
     380             :                 DWORD err = GetLastError();
     381             :                 GF_LOG(GF_LOG_WARNING, GF_LOG_MUTEX, ("[Thread %s] Couldn't set priority for thread ID 0x%08x, error %d\n", t->log_name, t->id, err));
     382             :         }
     383             : #endif
     384             : 
     385             : #else
     386             : 
     387             :         struct sched_param s_par;
     388           0 :         if (!t) return;
     389             : 
     390             :         /* consider this as real-time priority */
     391           0 :         if (priority > 200) {
     392           0 :                 s_par.sched_priority = priority - 200;
     393           0 :                 if (pthread_setschedparam(t->threadH, SCHED_RR, &s_par))
     394           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_MUTEX, ("[Thread %s] Couldn't set priority(1) for thread ID 0x%08x\n", t->log_name, t->id));
     395             :         } else {
     396           0 :                 s_par.sched_priority = priority;
     397           0 :                 if (pthread_setschedparam(t->threadH, SCHED_OTHER, &s_par))
     398           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_MUTEX, ("[Thread %s] Couldn't set priority(2) for thread ID 0x%08x\n", t->log_name, t->id));
     399             :         }
     400             : 
     401             : #endif
     402             : }
     403             : 
     404             : GF_EXPORT
     405         223 : u32 gf_th_status(GF_Thread *t)
     406             : {
     407         223 :         if (!t) return 0;
     408         223 :         return t->status;
     409             : }
     410             : 
     411             : 
     412             : GF_EXPORT
     413   748736017 : u32 gf_th_id()
     414             : {
     415             : #ifdef WIN32
     416             :         return ((u32) GetCurrentThreadId());
     417             : #else
     418   748736017 :         return ((u32) (PTR_TO_U_CAST(pthread_self())));
     419             : #endif
     420             : }
     421             : 
     422             : 
     423             : /*********************************************************************
     424             :                                                 OS-Specific Mutex Object
     425             : **********************************************************************/
     426             : struct __tag_mutex
     427             : {
     428             : #ifdef WIN32
     429             :         HANDLE hMutex;
     430             : #else
     431             :         pthread_mutex_t hMutex;
     432             : #endif
     433             :         /* We filter recursive calls (1 thread calling Lock several times in a row only locks
     434             :         ONCE the mutex. Holder is the current ThreadID of the mutex holder*/
     435             :         u32 Holder, HolderCount;
     436             : #ifndef GPAC_DISABLE_LOG
     437             :         char *log_name;
     438             : #endif
     439             : };
     440             : 
     441             : 
     442             : GF_EXPORT
     443       42100 : GF_Mutex *gf_mx_new(const char *name)
     444             : {
     445             : #ifndef WIN32
     446             :         pthread_mutexattr_t attr;
     447             : #endif
     448       42100 :         GF_Mutex *tmp = (GF_Mutex*)gf_malloc(sizeof(GF_Mutex));
     449       42100 :         if (!tmp) return NULL;
     450             :         memset(tmp, 0, sizeof(GF_Mutex));
     451             : 
     452             : #ifdef WIN32
     453             :         tmp->hMutex = CreateMutex(NULL, FALSE, NULL);
     454             :         if (!tmp->hMutex) {
     455             : #else
     456       42100 :         pthread_mutexattr_init(&attr);
     457       42100 :         if ( pthread_mutex_init(&tmp->hMutex, &attr) != 0 ) {
     458             : #endif
     459           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex] Couldn't create mutex %s\n", strlen(name) ? name : ""));
     460           0 :                 gf_free(tmp);
     461           0 :                 return NULL;
     462             :         }
     463             : 
     464             : #ifndef GPAC_DISABLE_LOG
     465       42100 :         if (name) {
     466       42100 :                 if (stricmp(name, "Logs")) {
     467       35859 :                         tmp->log_name = gf_strdup(name);
     468             :                 }
     469             :         } else {
     470             :                 char szN[20];
     471             :                 sprintf(szN, "%p", (void*)tmp);
     472           0 :                 tmp->log_name = gf_strdup(szN);
     473             :         }
     474             : #endif
     475             : 
     476             :         return tmp;
     477             : }
     478             : 
     479             : GF_EXPORT
     480       60711 : void gf_mx_del(GF_Mutex *mx)
     481             : {
     482             : #ifndef WIN32
     483             :         int err;
     484             : #endif
     485       60711 :         if (!mx) return;
     486             : 
     487             : #ifndef GPAC_DISABLE_LOG
     488       35867 :         if (mx->Holder && (gf_th_id() != mx->Holder) && mx->log_name) {
     489           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_MUTEX, ("[Mutex %s] Destroying mutex from thread %s but hold by thread %s\n", mx->log_name, log_th_name(gf_th_id() ), log_th_name(mx->Holder) ));
     490             :         }
     491             : #endif
     492             : 
     493             : #ifdef WIN32
     494             :         if (!CloseHandle(mx->hMutex)) {
     495             : #ifndef GPAC_DISABLE_LOG
     496             :                 if (mx->log_name) {
     497             :                         DWORD err = GetLastError();
     498             :                         GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex %s] CloseHandle when deleting mutex failed with error code %d\n", mx->log_name, err));
     499             :                 }
     500             : #endif
     501             :         }
     502             : #else
     503       35867 :         err = pthread_mutex_destroy(&mx->hMutex);
     504       35866 :         if (err) {
     505             : #ifndef GPAC_DISABLE_LOG
     506           0 :                 if (mx->log_name) {
     507           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex %s] pthread_mutex_destroy failed with error code %d\n", mx->log_name, err));
     508             :                 }
     509             : #endif
     510             :         }
     511             : 
     512             : #endif
     513             : #ifndef GPAC_DISABLE_LOG
     514       35866 :         if (mx->log_name) {
     515       29626 :                 gf_free(mx->log_name);
     516       29627 :                 mx->log_name = NULL;
     517             :         }
     518             : #endif
     519       35867 :         gf_free(mx);
     520             : }
     521             : 
     522             : GF_EXPORT
     523   357333075 : void gf_mx_v(GF_Mutex *mx)
     524             : {
     525             :         u32 caller;
     526   357333075 :         if (!mx) return;
     527   355985364 :         caller = gf_th_id();
     528             : 
     529             :         /*only if we own*/
     530             :         assert(caller == mx->Holder);
     531   355993869 :         if (caller != mx->Holder) return;
     532             :         assert(mx->HolderCount > 0);
     533   355995076 :         mx->HolderCount -= 1;
     534             : 
     535   355995076 :         if (mx->HolderCount == 0) {
     536             : #ifndef GPAC_DISABLE_LOG
     537   261353859 :                 if (mx->log_name) {
     538   261081100 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_MUTEX, ("[Mutex %s] At %d Released by thread %s\n", mx->log_name, gf_sys_clock(), log_th_name(mx->Holder) ));
     539             :                 }
     540             : #endif
     541   261341478 :                 mx->Holder = 0;
     542             : #ifdef WIN32
     543             :                 {
     544             :                         BOOL ret = ReleaseMutex(mx->hMutex);
     545             :                         if (!ret) {
     546             : #ifndef GPAC_DISABLE_LOG
     547             :                                 if (mx->log_name) {
     548             :                                         DWORD err = GetLastError();
     549             :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex] Couldn't release mutex (thread %s, error %d)\n", log_th_name(mx->Holder), err));
     550             :                                 }
     551             : #endif
     552             : 
     553             :                         }
     554             :                 }
     555             : #else
     556   261341478 :                 if (pthread_mutex_unlock(&mx->hMutex)) {
     557             : #ifndef GPAC_DISABLE_LOG
     558           0 :                         if (mx->log_name) {
     559           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex] Couldn't release mutex (thread %s)\n", log_th_name(mx->Holder)));
     560             :                         }
     561             : #endif
     562             :                 }
     563             : #endif
     564             :         }
     565             : }
     566             : 
     567             : GF_EXPORT
     568   357320483 : u32 gf_mx_p(GF_Mutex *mx)
     569             : {
     570             : #ifndef WIN32
     571             :         int retCode;
     572             : #endif
     573             :         u32 caller;
     574             : #ifndef GPAC_DISABLE_LOG
     575             :         const char *mx_holder_name;
     576             : #endif
     577             : 
     578   357320483 :         if (!mx) return 1;
     579   355974589 :         caller = gf_th_id();
     580   355993128 :         if (caller == mx->Holder) {
     581    94643722 :                 mx->HolderCount += 1;
     582    94643722 :                 return 1;
     583             :         }
     584             : 
     585             : #ifndef GPAC_DISABLE_LOG
     586   261349406 :         mx_holder_name = mx->Holder ? log_th_name(mx->Holder) : "none";
     587   261349066 :         if (mx->Holder && mx->log_name)
     588       10252 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_MUTEX, ("[Mutex %s] At %d Thread %s waiting a release from thread %s\n", mx->log_name, gf_sys_clock(), log_th_name(caller), mx_holder_name ));
     589             : #endif
     590             : 
     591             : #ifdef WIN32
     592             :         switch (WaitForSingleObject(mx->hMutex, INFINITE)) {
     593             :         case WAIT_ABANDONED:
     594             :         case WAIT_TIMEOUT:
     595             :                 return 0;
     596             :         default:
     597             :                 break;
     598             :         }
     599             : #else
     600   261349066 :         retCode = pthread_mutex_lock(&mx->hMutex);
     601   261355656 :         if (retCode != 0 ) {
     602             : #ifndef GPAC_DISABLE_LOG
     603           0 :                 if (mx->log_name) {
     604           0 :                         if (retCode == EINVAL)
     605           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex %p=%s] Not properly initialized.\n", mx, mx->log_name));
     606           0 :                         if (retCode == EDEADLK)
     607           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex %p=%s] Deadlock detected.\n", mx, mx->log_name));
     608             :                 }
     609             : #endif /* GPAC_DISABLE_LOG */
     610             :                 assert(0);
     611             :                 return 0;
     612             :         }
     613             : #endif /* NOT WIN32 */
     614   261355656 :         mx->HolderCount = 1;
     615   261355656 :         mx->Holder = caller;
     616             : #ifndef GPAC_DISABLE_LOG
     617   261355656 :         if (mx->log_name) {
     618   261082706 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_MUTEX, ("[Mutex %s] At %d Grabbed by thread %s\n", mx->log_name, gf_sys_clock(), log_th_name(mx->Holder) ));
     619             :         }
     620             : #endif
     621             :         return 1;
     622             : }
     623             : 
     624             : 
     625             : GF_EXPORT
     626           1 : s32 gf_mx_get_num_locks(GF_Mutex *mx)
     627             : {
     628             :         u32 caller;
     629           1 :         if (!mx) return 0;
     630           0 :         caller = gf_th_id();
     631           0 :         if (caller == mx->Holder) {
     632           0 :                 return mx->HolderCount;
     633             :         }
     634             :         return -1;
     635             : }
     636             : 
     637             : GF_EXPORT
     638        5270 : Bool gf_mx_try_lock(GF_Mutex *mx)
     639             : {
     640             :         u32 caller;
     641        5270 :         if (!mx) return GF_FALSE;
     642        5270 :         caller = gf_th_id();
     643        5270 :         if (caller == mx->Holder) {
     644        1659 :                 mx->HolderCount += 1;
     645        1659 :                 return GF_TRUE;
     646             :         }
     647             : 
     648             : #ifdef WIN32
     649             :         /*is the object signaled?*/
     650             :         switch (WaitForSingleObject(mx->hMutex, 0)) {
     651             :         case WAIT_OBJECT_0:
     652             :                 break;
     653             :         case WAIT_ABANDONED:
     654             :         case WAIT_TIMEOUT:
     655             : #ifndef GPAC_DISABLE_LOG
     656             :                 if (mx->log_name) {
     657             :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_MUTEX, ("[Mutex %s] At %d Couldn't be locked by thread %s (grabbed by thread %s)\n", mx->log_name, gf_sys_clock(), log_th_name(caller), log_th_name(mx->Holder) ));
     658             :                 }
     659             : #endif
     660             :                 return GF_FALSE;
     661             :         case WAIT_FAILED:
     662             : #ifndef GPAC_DISABLE_LOG
     663             :                 if (mx->log_name) {
     664             :                         GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex %s] At %d WaitForSingleObject failed\n", mx->log_name, gf_sys_clock()));
     665             :                         return GF_FALSE;
     666             :                 }
     667             : #endif
     668             :         default:
     669             :                 assert(0);
     670             :                 return GF_FALSE;
     671             :         }
     672             : #else
     673        3611 :         if (pthread_mutex_trylock(&mx->hMutex) != 0 ) {
     674             : #ifndef GPAC_DISABLE_LOG
     675           2 :                 if (mx->log_name) {
     676           2 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_MUTEX, ("[Mutex %s] At %d Couldn't release it for thread %s (grabbed by thread %s)\n", mx->log_name, gf_sys_clock(), log_th_name(caller), log_th_name(mx->Holder) ));
     677             :                 }
     678             : #endif
     679             :                 return GF_FALSE;
     680             :         }
     681             : #endif
     682        3609 :         mx->Holder = caller;
     683        3609 :         mx->HolderCount = 1;
     684             : #ifndef GPAC_DISABLE_LOG
     685        3609 :         if (mx->log_name) {
     686        3609 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_MUTEX, ("[Mutex %s] At %d Grabbed by thread %s\n", mx->log_name, gf_sys_clock(), log_th_name(mx->Holder) ));
     687             :         }
     688             : #endif
     689             :         return GF_TRUE;
     690             : }
     691             : 
     692             : 
     693             : /*********************************************************************
     694             :                                                 OS-Specific Semaphore Object
     695             : **********************************************************************/
     696             : struct __tag_semaphore
     697             : {
     698             : #ifdef WIN32
     699             :         HANDLE hSemaphore;
     700             : #else
     701             :         sem_t *hSemaphore;
     702             :         sem_t SemaData;
     703             : #if defined(__DARWIN__) || defined(__APPLE__)
     704             :         char *SemName;
     705             : #endif
     706             : #endif
     707             : };
     708             : 
     709             : GF_EXPORT
     710         436 : GF_Semaphore *gf_sema_new(u32 MaxCount, u32 InitCount)
     711             : {
     712         436 :         GF_Semaphore *tmp = (GF_Semaphore*)gf_malloc(sizeof(GF_Semaphore));
     713         436 :         if (!tmp) {
     714           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("Couldn't allocate semaphore\n"));
     715             :                 return NULL;
     716             :         }
     717             : 
     718             : #if defined(WIN32)
     719             :         MaxCount = MIN(MaxCount, GF_INT_MAX);
     720             :         tmp->hSemaphore = CreateSemaphore(NULL, InitCount, MIN(MaxCount, GF_INT_MAX), NULL);
     721             :         if (!tmp->hSemaphore) {
     722             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("Couldn't create semaphore\n"));
     723             :                 gf_free(tmp);
     724             :                 return NULL;
     725             :         }
     726             : 
     727             : #elif defined(__DARWIN__) || defined(__APPLE__)
     728             :         /* sem_init isn't supported on Mac OS X 10.3 & 10.4; it returns ENOSYS
     729             :         To get around this, a NAMED semaphore needs to be used
     730             :         sem_t *sem_open(const char *name, int oflag, ...);
     731             :         http://users.evitech.fi/~hannuvl/ke04/reaaliaika_ohj/memmap_named_semaphores.c
     732             :         */
     733             :         {
     734             :                 char semaName[40];
     735             :                 u64 add = (u64) tmp ^ gf_net_get_utc() ^ gf_rand();
     736             :                 sprintf(semaName,"GPAC_SEM"LLU, add);
     737             :                 tmp->SemName = gf_strdup(semaName);
     738             :         }
     739             :         sem_unlink(tmp->SemName);
     740             :         tmp->hSemaphore = sem_open(tmp->SemName, O_CREAT, S_IRUSR|S_IWUSR, InitCount);
     741             :         if (tmp->hSemaphore==SEM_FAILED) {
     742             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("Couldn't init semaphore: error %d\n", errno));
     743             :                 gf_free(tmp);
     744             :                 return NULL;
     745             :         }
     746             : #else
     747         436 :         if (sem_init(&tmp->SemaData, 0, InitCount) < 0 ) {
     748           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("Couldn't init semaphore: error %d\n", errno));
     749           0 :                 gf_free(tmp);
     750           0 :                 return NULL;
     751             :         }
     752         436 :         tmp->hSemaphore = &tmp->SemaData;
     753             : #endif
     754         436 :         return tmp;
     755             : }
     756             : 
     757             : GF_EXPORT
     758         434 : void gf_sema_del(GF_Semaphore *sm)
     759             : {
     760         434 :         if (!sm) return;
     761             : #if defined(WIN32)
     762             :         if (!CloseHandle(sm->hSemaphore)) {
     763             :                 DWORD err = GetLastError();
     764             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex] CloseHandle when deleting semaphore failed with error code %d\n", err));
     765             :         }
     766             : #elif defined(__DARWIN__) || defined(__APPLE__)
     767             :         sem_close(sm->hSemaphore);
     768             :         sem_unlink(sm->SemName);
     769             :         gf_free(sm->SemName);
     770             : #else
     771         434 :         sem_destroy(sm->hSemaphore);
     772             : #endif
     773         434 :         gf_free(sm);
     774             : }
     775             : 
     776             : GF_EXPORT
     777     1978559 : Bool gf_sema_notify(GF_Semaphore *sm, u32 NbRelease)
     778             : {
     779             : #ifndef WIN32
     780             :         sem_t *hSem;
     781             : #else
     782             :         u32 prevCount=0;
     783             : #endif
     784             : 
     785     1978559 :         if (!sm) return GF_FALSE;
     786             : 
     787             : #if defined(WIN32)
     788             :         ReleaseSemaphore(sm->hSemaphore, NbRelease, (LPLONG) &prevCount);
     789             : #else
     790             : 
     791     1973187 :         hSem = sm->hSemaphore;
     792             : 
     793     7180992 :         while (NbRelease) {
     794     3237065 :                 if (sem_post(hSem) < 0) return GF_FALSE;
     795     3234618 :                 NbRelease -= 1;
     796             :         }
     797             : #endif
     798             :         return GF_TRUE;
     799             : }
     800             : 
     801             : GF_EXPORT
     802     1397333 : Bool gf_sema_wait(GF_Semaphore *sm)
     803             : {
     804     1397333 :         if (!sm) return GF_FALSE;
     805             : #ifdef WIN32
     806             :         switch (WaitForSingleObject(sm->hSemaphore, INFINITE) ) {
     807             :         case WAIT_FAILED:
     808             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Semaphore] failed to wait: %d\n", GetLastError() ));
     809             :                 return GF_FALSE;
     810             :         case WAIT_ABANDONED:
     811             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Semaphore] failed to wait: owner thread exit\n"));
     812             :                 return GF_FALSE;
     813             :         default:
     814             :                 break;
     815             :         }
     816             : 
     817             : #else
     818     1397362 :         if (sem_wait(sm->hSemaphore) < 0) {
     819           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Semaphore] failed to wait for semaphore: %d\n", errno));
     820             :                 return GF_FALSE;
     821             :         }
     822             : #endif
     823             :         return GF_TRUE;
     824             : }
     825             : 
     826             : GF_EXPORT
     827        4306 : Bool gf_sema_wait_for(GF_Semaphore *sm, u32 TimeOut)
     828             : {
     829             : #ifdef WIN32
     830             :         if (!sm) return GF_FALSE;
     831             :         if (WaitForSingleObject(sm->hSemaphore, TimeOut) == WAIT_TIMEOUT) return GF_FALSE;
     832             :         return GF_TRUE;
     833             : #else
     834             :         sem_t *hSem;
     835        4306 :         if (!sm) return GF_FALSE;
     836        4344 :         hSem = sm->hSemaphore;
     837             : 
     838        4344 :         if (!TimeOut) {
     839           0 :                 if (!sem_trywait(hSem)) return GF_TRUE;
     840           0 :                 return GF_FALSE;
     841             :         }
     842             : 
     843             : #if defined(__DARWIN__) || defined(__APPLE__) || defined(GPAC_CONFIG_IOS)
     844             : 
     845             :         TimeOut += gf_sys_clock();
     846             :         do {
     847             :                 if (!sem_trywait(hSem)) return GF_TRUE;
     848             :                 //OSX/ios don't support sem_timedwait, so we sleep until the sem is notified or the timeout is done
     849             :                 //don't be too greedy, use 5ms sleep
     850             :                 //another approach would be to spawn a thread, use sem_wait and send an interrupt on the sema after the timeout ...
     851             :                 gf_sleep(1);
     852             :         } while (gf_sys_clock() < TimeOut);
     853             :         return GF_FALSE;
     854             : #else
     855             :         struct timespec tv;
     856             :         u32 secs;
     857        4344 :         if (clock_gettime(CLOCK_REALTIME, &tv) == -1) return GF_FALSE;
     858        4315 :         secs = TimeOut/1000;
     859        4315 :         tv.tv_sec += secs;
     860        4315 :         tv.tv_nsec += (u64) ((TimeOut-secs*1000)) * 1000000;
     861        4315 :         if (tv.tv_nsec>1000000000) {
     862         190 :                 tv.tv_nsec -= 1000000000;
     863         190 :                 tv.tv_sec += 1;
     864             :         }
     865        4315 :         if (!sem_timedwait(hSem, &tv)) return GF_TRUE;
     866             : 
     867           0 :         return GF_FALSE;
     868             : #endif
     869             : 
     870             : #endif
     871             : }
     872             : 
     873             : #endif

Generated by: LCOV version 1.13