LCOV - code coverage report
Current view: top level - src/utils - tds_cond.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 13 13 100.0 %
Date: 2026-04-15 18:41:20 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 2012  Frediano Ziglio
       3             :  *
       4             :  * This library is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU Library General Public
       6             :  * License as published by the Free Software Foundation; either
       7             :  * version 2 of the License, or (at your option) any later version.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             :  * Library General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU Library General Public
      15             :  * License along with this library; if not, write to the
      16             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      17             :  * Boston, MA 02111-1307, USA.
      18             :  */
      19             : 
      20             : #include <config.h>
      21             : 
      22             : #if HAVE_STDLIB_H
      23             : #include <stdlib.h>
      24             : #endif /* HAVE_STDLIB_H */
      25             : 
      26             : #ifdef _WIN32
      27             : 
      28             : #if HAVE_STRING_H
      29             : #include <string.h>
      30             : #endif /* HAVE_STRING_H */
      31             : 
      32             : #include <freetds/thread.h>
      33             : #include <freetds/time.h>
      34             : #include <freetds/macros.h>
      35             : 
      36             : /* implementation for systems that support Condition Variables */
      37             : typedef VOID(WINAPI * init_cv_t) (TDS_CONDITION_VARIABLE * cv);
      38             : typedef BOOL(WINAPI * sleep_cv_t) (TDS_CONDITION_VARIABLE * cv, PSRWLOCK lock, DWORD milli, ULONG flags);
      39             : typedef VOID(WINAPI * wake_cv_t) (TDS_CONDITION_VARIABLE * cv);
      40             : typedef VOID(WINAPI * srwinit_cv_t) (PSRWLOCK lock);
      41             : typedef VOID(WINAPI * srwlock_cv_t) (PSRWLOCK lock);
      42             : typedef VOID(WINAPI * srwunlock_cv_t) (PSRWLOCK lock);
      43             : typedef BOOLEAN(WINAPI * srwtrylock_cv_t) (PSRWLOCK lock);
      44             : 
      45             : static init_cv_t init_cv = NULL;
      46             : static sleep_cv_t sleep_cv = NULL;
      47             : static wake_cv_t wake_cv = NULL;
      48             : static srwinit_cv_t srwinit_cv = NULL;
      49             : static srwlock_cv_t srwlock_cv = NULL;
      50             : static srwunlock_cv_t srwunlock_cv = NULL;
      51             : static srwtrylock_cv_t srwtrylock_cv = NULL;
      52             : 
      53             : static int
      54             : new_mutex_init(tds_raw_mutex *mtx)
      55             : {
      56             :         srwinit_cv(&mtx->srwlock);
      57             :         return 0;
      58             : }
      59             : 
      60             : static void
      61             : new_mutex_free(tds_raw_mutex *mtx TDS_UNUSED)
      62             : {
      63             : }
      64             : 
      65             : static void
      66             : new_mutex_lock(tds_raw_mutex *mtx)
      67             : {
      68             :         srwlock_cv(&mtx->srwlock);
      69             : }
      70             : 
      71             : static void
      72             : new_mutex_unlock(tds_raw_mutex *mtx)
      73             : {
      74             :         srwunlock_cv(&mtx->srwlock);
      75             : }
      76             : 
      77             : static int
      78             : new_mutex_trylock(tds_raw_mutex *mtx)
      79             : {
      80             :         return srwtrylock_cv(&mtx->srwlock) ? 0 : -1;
      81             : }
      82             : 
      83             : static int
      84             : new_cond_init(tds_condition *cond)
      85             : {
      86             :         init_cv(&cond->cv);
      87             :         return 0;
      88             : }
      89             : 
      90             : static int
      91             : new_cond_destroy(tds_condition * cond TDS_UNUSED)
      92             : {
      93             :         return 0;
      94             : }
      95             : 
      96             : static int
      97             : new_cond_signal(tds_condition * cond)
      98             : {
      99             :         wake_cv(&cond->cv);
     100             :         return 0;
     101             : }
     102             : 
     103             : static int
     104             : new_cond_timedwait(tds_condition *cond, tds_raw_mutex *mtx, int timeout_sec)
     105             : {
     106             :         if (sleep_cv(&cond->cv, &mtx->srwlock, timeout_sec <= 0 ? INFINITE : timeout_sec * 1000, 0))
     107             :                 return 0;
     108             :         return ETIMEDOUT;
     109             : }
     110             : 
     111             : 
     112             : /* Implementation for systems that do not support Condition Variables.
     113             :  *
     114             :  * These are very old systems (like Windows XP), we don't care much about,
     115             :  * just to make them run without much expectations.
     116             :  *
     117             :  * We reuse "srwlock.Ptr" to store a pointer to a structure with a
     118             :  * CRITICAL_SECTION in it.
     119             :  */
     120             : typedef struct
     121             : {
     122             :         CRITICAL_SECTION crit;
     123             :         DWORD thread_id;
     124             : } old_mutex;
     125             : 
     126             : static old_mutex *
     127             : old_mutex_allocate(tds_raw_mutex *mtx)
     128             : {
     129             :         old_mutex *res, *old_mtx;
     130             : 
     131             :         /* Allocate and initialize structure. */
     132             :         old_mtx = calloc(1, sizeof(old_mutex));
     133             :         if (!old_mtx)
     134             :                 abort();
     135             :         InitializeCriticalSection(&old_mtx->crit);
     136             : 
     137             :         /* Hook to srwlock.Ptr, undo if it was set in the meantime. */
     138             :         res = InterlockedCompareExchangePointer(&mtx->srwlock.Ptr, old_mtx, NULL);
     139             :         if (res == NULL)
     140             :                 return old_mtx;
     141             : 
     142             :         DeleteCriticalSection(&old_mtx->crit);
     143             :         free(old_mtx);
     144             :         return res;
     145             : }
     146             : 
     147             : static int
     148             : old_mutex_init(tds_raw_mutex *mtx)
     149             : {
     150             :         mtx->srwlock.Ptr = NULL;
     151             :         old_mutex_allocate(mtx);
     152             :         return 0;
     153             : }
     154             : 
     155             : static void
     156             : old_mutex_free(tds_raw_mutex *mtx)
     157             : {
     158             :         old_mutex *old_mtx = InterlockedExchangePointer(&mtx->srwlock.Ptr, NULL);
     159             : 
     160             :         if (old_mtx) {
     161             :                 DeleteCriticalSection(&old_mtx->crit);
     162             :                 free(old_mtx);
     163             :         }
     164             : }
     165             : 
     166             : static void
     167             : old_mutex_lock(tds_raw_mutex *mtx)
     168             : {
     169             :         old_mutex *old_mtx = mtx->srwlock.Ptr;
     170             : 
     171             :         if (!old_mtx)
     172             :                 old_mtx = old_mutex_allocate(mtx);
     173             : 
     174             :         EnterCriticalSection(&old_mtx->crit);
     175             :         old_mtx->thread_id = GetCurrentThreadId();
     176             : }
     177             : 
     178             : static void
     179             : old_mutex_unlock(tds_raw_mutex *mtx)
     180             : {
     181             :         old_mutex *old_mtx = mtx->srwlock.Ptr;
     182             : 
     183             :         old_mtx->thread_id = 0;
     184             :         LeaveCriticalSection(&old_mtx->crit);
     185             : }
     186             : 
     187             : static int
     188             : old_mutex_trylock(tds_raw_mutex *mtx)
     189             : {
     190             :         old_mutex *old_mtx = mtx->srwlock.Ptr;
     191             : 
     192             :         if (!old_mtx)
     193             :                 old_mtx = old_mutex_allocate(mtx);
     194             : 
     195             :         if (TryEnterCriticalSection(&old_mtx->crit)) {
     196             :                 DWORD thread_id = GetCurrentThreadId();
     197             : 
     198             :                 if (old_mtx->thread_id == thread_id) {
     199             :                         LeaveCriticalSection(&old_mtx->crit);
     200             :                         return -1;
     201             :                 }
     202             :                 old_mtx->thread_id = thread_id;
     203             :                 return 0;
     204             :         }
     205             :         return -1;
     206             : }
     207             : 
     208             : static int
     209             : old_cond_init(tds_condition *cond)
     210             : {
     211             :         cond->ev = CreateEvent(NULL, FALSE, FALSE, NULL);
     212             :         if (!cond->ev)
     213             :                 return ENOMEM;
     214             :         return 0;
     215             : }
     216             : 
     217             : static int
     218             : old_cond_destroy(tds_condition * cond)
     219             : {
     220             :         CloseHandle(cond->ev);
     221             :         return 0;
     222             : }
     223             : 
     224             : static int
     225             : old_cond_signal(tds_condition * cond)
     226             : {
     227             :         SetEvent(cond->ev);
     228             :         return 0;
     229             : }
     230             : 
     231             : static int
     232             : old_cond_timedwait(tds_condition *cond, tds_raw_mutex *mtx, int timeout_sec)
     233             : {
     234             :         old_mutex *old_mtx = mtx->srwlock.Ptr;
     235             :         int res;
     236             : 
     237             :         LeaveCriticalSection(&old_mtx->crit);
     238             :         res = WaitForSingleObject(cond->ev, timeout_sec <= 0 ? INFINITE : timeout_sec * 1000);
     239             :         EnterCriticalSection(&old_mtx->crit);
     240             :         return res == WAIT_TIMEOUT ? ETIMEDOUT : 0;
     241             : }
     242             : 
     243             : 
     244             : /* dummy implementation used to detect which version above to use */
     245             : static void
     246             : detect_cond(void)
     247             : {
     248             :         /* detect if this Windows support condition variables and SRWLocks */
     249             :         HMODULE mod = GetModuleHandle(TEXT("kernel32"));
     250             : 
     251             :         if (mod) {
     252             :                 init_cv = (init_cv_t) GetProcAddress(mod, "InitializeConditionVariable");
     253             :                 sleep_cv = (sleep_cv_t) GetProcAddress(mod, "SleepConditionVariableSRW");
     254             :                 wake_cv = (wake_cv_t) GetProcAddress(mod, "WakeConditionVariable");
     255             :                 srwinit_cv = (srwinit_cv_t) GetProcAddress(mod, "InitializeSRWLock");
     256             :                 srwlock_cv = (srwlock_cv_t) GetProcAddress(mod, "AcquireSRWLockExclusive");
     257             :                 srwunlock_cv = (srwunlock_cv_t) GetProcAddress(mod, "ReleaseSRWLockExclusive");
     258             :                 srwtrylock_cv = (srwtrylock_cv_t) GetProcAddress(mod, "TryAcquireSRWLockExclusive");
     259             :         }
     260             : 
     261             :         if (init_cv && sleep_cv && wake_cv && srwinit_cv && srwlock_cv && srwunlock_cv && srwtrylock_cv) {
     262             :                 tds_raw_mutex_init = new_mutex_init;
     263             :                 tds_raw_mutex_free = new_mutex_free;
     264             :                 tds_raw_mutex_lock = new_mutex_lock;
     265             :                 tds_raw_mutex_unlock = new_mutex_unlock;
     266             :                 tds_raw_mutex_trylock = new_mutex_trylock;
     267             : 
     268             :                 tds_raw_cond_init = new_cond_init;
     269             :                 tds_raw_cond_destroy = new_cond_destroy;
     270             :                 tds_raw_cond_signal = new_cond_signal;
     271             :                 tds_raw_cond_timedwait = new_cond_timedwait;
     272             :         } else {
     273             :                 tds_raw_mutex_init = old_mutex_init;
     274             :                 tds_raw_mutex_free = old_mutex_free;
     275             :                 tds_raw_mutex_lock = old_mutex_lock;
     276             :                 tds_raw_mutex_unlock = old_mutex_unlock;
     277             :                 tds_raw_mutex_trylock = old_mutex_trylock;
     278             : 
     279             :                 tds_raw_cond_init = old_cond_init;
     280             :                 tds_raw_cond_destroy = old_cond_destroy;
     281             :                 tds_raw_cond_signal = old_cond_signal;
     282             :                 tds_raw_cond_timedwait = old_cond_timedwait;
     283             :         }
     284             : }
     285             : 
     286             : static int
     287             : detect_mutex_init(tds_raw_mutex *mtx)
     288             : {
     289             :         detect_cond();
     290             :         return tds_raw_mutex_init(mtx);
     291             : }
     292             : 
     293             : static void
     294             : detect_mutex_free(tds_raw_mutex *mtx)
     295             : {
     296             :         detect_cond();
     297             :         tds_raw_mutex_free(mtx);
     298             : }
     299             : 
     300             : static void
     301             : detect_mutex_lock(tds_raw_mutex *mtx)
     302             : {
     303             :         detect_cond();
     304             :         tds_raw_mutex_lock(mtx);
     305             : }
     306             : 
     307             : static void
     308             : detect_mutex_unlock(tds_raw_mutex *mtx)
     309             : {
     310             :         detect_cond();
     311             :         tds_raw_mutex_unlock(mtx);
     312             : }
     313             : 
     314             : static int
     315             : detect_mutex_trylock(tds_raw_mutex *mtx)
     316             : {
     317             :         detect_cond();
     318             :         return tds_raw_mutex_trylock(mtx);
     319             : }
     320             : 
     321             : static int
     322             : detect_cond_init(tds_condition *cond)
     323             : {
     324             :         detect_cond();
     325             :         return tds_raw_cond_init(cond);
     326             : }
     327             : 
     328             : static int
     329             : detect_cond_destroy(tds_condition * cond)
     330             : {
     331             :         detect_cond();
     332             :         return tds_raw_cond_destroy(cond);
     333             : }
     334             : 
     335             : static int
     336             : detect_cond_signal(tds_condition * cond)
     337             : {
     338             :         detect_cond();
     339             :         return tds_raw_cond_signal(cond);
     340             : }
     341             : 
     342             : static int
     343             : detect_cond_timedwait(tds_condition * cond, tds_raw_mutex * mtx, int timeout_sec)
     344             : {
     345             :         detect_cond();
     346             :         return tds_raw_cond_timedwait(cond, mtx, timeout_sec);
     347             : }
     348             : 
     349             : int (*tds_raw_mutex_init)(tds_raw_mutex * mtx) = detect_mutex_init;
     350             : void (*tds_raw_mutex_free)(tds_raw_mutex * mtx) = detect_mutex_free;
     351             : void (*tds_raw_mutex_lock)(tds_raw_mutex * mtx) = detect_mutex_lock;
     352             : void (*tds_raw_mutex_unlock)(tds_raw_mutex * mtx) = detect_mutex_unlock;
     353             : int (*tds_raw_mutex_trylock)(tds_raw_mutex * mtx) = detect_mutex_trylock;
     354             : 
     355             : int (*tds_raw_cond_init)(tds_condition * cond) = detect_cond_init;
     356             : int (*tds_raw_cond_destroy)(tds_condition * cond) = detect_cond_destroy;
     357             : int (*tds_raw_cond_signal)(tds_condition * cond) = detect_cond_signal;
     358             : int (*tds_raw_cond_timedwait) (tds_condition * cond, tds_raw_mutex * mtx, int timeout_sec) = detect_cond_timedwait;
     359             : 
     360             : #elif defined(TDS_HAVE_PTHREAD_MUTEX) && !defined(TDS_NO_THREADSAFE)
     361             : 
     362             : #include <freetds/thread.h>
     363             : #include <freetds/time.h>
     364             : 
     365             : /* check if we can use pthread_cond_timedwait_relative_np */
     366             : #undef USE_COND_TIMEDWAIT_RELATIVE
     367             : #if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP) && \
     368             :         (!defined(__ANDROID__) || ((__ANDROID_API__ < 21) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)))
     369             : #define USE_COND_TIMEDWAIT_RELATIVE 1
     370             : #endif
     371             : 
     372             : /* check if we can use clock_gettime */
     373             : #undef USE_CLOCK_GETTIME_IN_COND
     374             : #if !defined(USE_COND_TIMEDWAIT_RELATIVE) && \
     375             :         defined(HAVE_CLOCK_GETTIME) && (defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC))
     376             : #define USE_CLOCK_GETTIME_IN_COND 1
     377             : #endif
     378             : 
     379             : /* check if we can use CLOCK_MONOTONIC for conditions */
     380             : #undef USE_MONOTONIC_CLOCK_IN_COND
     381             : #if defined(USE_CLOCK_GETTIME_IN_COND) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(CLOCK_MONOTONIC)
     382             : #define USE_MONOTONIC_CLOCK_IN_COND 1
     383             : #endif
     384             : 
     385        2365 : int tds_raw_cond_init(tds_condition *cond)
     386             : {
     387             : #ifdef USE_MONOTONIC_CLOCK_IN_COND
     388             :         int res;
     389             :         pthread_condattr_t attr;
     390             : 
     391        2365 :         pthread_condattr_init(&attr);
     392        2365 :         res = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
     393        2365 :         if (!res)
     394        2365 :                 res = pthread_cond_init(cond, &attr);
     395        2365 :         pthread_condattr_destroy(&attr);
     396        2365 :         return res;
     397             : #else
     398             :         return pthread_cond_init(cond, NULL);
     399             : #endif
     400             : }
     401             : 
     402          40 : int tds_raw_cond_timedwait(tds_condition *cond, tds_raw_mutex *mtx, int timeout_sec)
     403             : {
     404             :         struct timespec ts;
     405             : 
     406          40 :         if (timeout_sec <= 0)
     407          20 :                 return tds_raw_cond_wait(cond, mtx);
     408             : 
     409             : #if defined(USE_COND_TIMEDWAIT_RELATIVE)
     410             :         ts.tv_sec = timeout_sec;
     411             :         ts.tv_nsec = 0;
     412             :         return pthread_cond_timedwait_relative_np(cond, mtx, &ts);
     413             : #else
     414             : 
     415             : #  if defined(USE_MONOTONIC_CLOCK_IN_COND)
     416          20 :         clock_gettime(CLOCK_MONOTONIC, &ts);
     417             : #  elif defined(USE_CLOCK_GETTIME_IN_COND)
     418             :         clock_gettime(CLOCK_REALTIME, &ts);
     419             : #  elif defined(HAVE_GETTIMEOFDAY)
     420             :         do {
     421             :                 struct timeval tv;
     422             :                 gettimeofday(&tv, NULL);
     423             :                 ts.tv_sec = tv.tv_sec;
     424             :                 ts.tv_nsec = tv.tv_usec * 1000u;
     425             :         } while(0);
     426             : #  else
     427             : #  error No way to get a proper time!
     428             : #  endif
     429             : 
     430          20 :         ts.tv_sec += timeout_sec;
     431          20 :         return pthread_cond_timedwait(cond, mtx, &ts);
     432             : #endif
     433             : }
     434             : 
     435             : #endif

Generated by: LCOV version 1.13