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: 2025-01-18 12:13:41 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             : 
      35             : /* implementation for systems that support Condition Variables */
      36             : typedef VOID(WINAPI * init_cv_t) (TDS_CONDITION_VARIABLE * cv);
      37             : typedef BOOL(WINAPI * sleep_cv_t) (TDS_CONDITION_VARIABLE * cv, CRITICAL_SECTION * crit, DWORD milli);
      38             : typedef VOID(WINAPI * wake_cv_t) (TDS_CONDITION_VARIABLE * cv);
      39             : 
      40             : static init_cv_t init_cv = NULL;
      41             : static sleep_cv_t sleep_cv = NULL;
      42             : static wake_cv_t wake_cv = NULL;
      43             : 
      44             : static int
      45             : new_cond_init(tds_condition * cond)
      46             : {
      47             :         init_cv(&cond->cv);
      48             :         return 0;
      49             : }
      50             : 
      51             : static int
      52             : new_cond_destroy(tds_condition * cond)
      53             : {
      54             :         return 0;
      55             : }
      56             : 
      57             : static int
      58             : new_cond_signal(tds_condition * cond)
      59             : {
      60             :         wake_cv(&cond->cv);
      61             :         return 0;
      62             : }
      63             : 
      64             : static int
      65             : new_cond_timedwait(tds_condition * cond, tds_raw_mutex * mtx, int timeout_sec)
      66             : {
      67             :         if (sleep_cv(&cond->cv, &mtx->crit, timeout_sec <= 0 ? INFINITE : timeout_sec * 1000))
      68             :                 return 0;
      69             :         return ETIMEDOUT;
      70             : }
      71             : 
      72             : 
      73             : /* implementation for systems that do not support Condition Variables */
      74             : static int
      75             : old_cond_init(tds_condition * cond)
      76             : {
      77             :         cond->ev = CreateEvent(NULL, FALSE, FALSE, NULL);
      78             :         if (!cond->ev)
      79             :                 return ENOMEM;
      80             :         return 0;
      81             : }
      82             : 
      83             : static int
      84             : old_cond_destroy(tds_condition * cond)
      85             : {
      86             :         CloseHandle(cond->ev);
      87             :         return 0;
      88             : }
      89             : 
      90             : static int
      91             : old_cond_signal(tds_condition * cond)
      92             : {
      93             :         SetEvent(cond->ev);
      94             :         return 0;
      95             : }
      96             : 
      97             : static int
      98             : old_cond_timedwait(tds_condition * cond, tds_raw_mutex * mtx, int timeout_sec)
      99             : {
     100             :         int res;
     101             : 
     102             :         LeaveCriticalSection(&mtx->crit);
     103             :         res = WaitForSingleObject(cond->ev, timeout_sec < 0 ? INFINITE : timeout_sec * 1000);
     104             :         EnterCriticalSection(&mtx->crit);
     105             :         return res == WAIT_TIMEOUT ? ETIMEDOUT : 0;
     106             : }
     107             : 
     108             : 
     109             : /* dummy implementation used to detect which version above to use */
     110             : static void
     111             : detect_cond(void)
     112             : {
     113             :         /* detect if this Windows support condition variables */
     114             :         HMODULE mod = GetModuleHandle(TEXT("kernel32"));
     115             : 
     116             :         init_cv  = (init_cv_t)  GetProcAddress(mod, "InitializeConditionVariable");
     117             :         sleep_cv = (sleep_cv_t) GetProcAddress(mod, "SleepConditionVariableCS");
     118             :         wake_cv  = (wake_cv_t)  GetProcAddress(mod, "WakeConditionVariable");
     119             : 
     120             :         if (init_cv && sleep_cv && wake_cv) {
     121             :                 tds_raw_cond_init      = new_cond_init;
     122             :                 tds_raw_cond_destroy   = new_cond_destroy;
     123             :                 tds_raw_cond_signal    = new_cond_signal;
     124             :                 tds_raw_cond_timedwait = new_cond_timedwait;
     125             :         } else {
     126             :                 tds_raw_cond_init      = old_cond_init;
     127             :                 tds_raw_cond_destroy   = old_cond_destroy;
     128             :                 tds_raw_cond_signal    = old_cond_signal;
     129             :                 tds_raw_cond_timedwait = old_cond_timedwait;
     130             :         }
     131             : }
     132             : 
     133             : static int
     134             : detect_cond_init(tds_condition * cond)
     135             : {
     136             :         detect_cond();
     137             :         return tds_raw_cond_init(cond);
     138             : }
     139             : 
     140             : static int
     141             : detect_cond_destroy(tds_condition * cond)
     142             : {
     143             :         detect_cond();
     144             :         return tds_raw_cond_destroy(cond);
     145             : }
     146             : 
     147             : static int
     148             : detect_cond_signal(tds_condition * cond)
     149             : {
     150             :         detect_cond();
     151             :         return tds_raw_cond_signal(cond);
     152             : }
     153             : 
     154             : static int
     155             : detect_cond_timedwait(tds_condition * cond, tds_raw_mutex * mtx, int timeout_sec)
     156             : {
     157             :         detect_cond();
     158             :         return tds_raw_cond_timedwait(cond, mtx, timeout_sec);
     159             : }
     160             : 
     161             : int (*tds_raw_cond_init) (tds_condition * cond) = detect_cond_init;
     162             : int (*tds_raw_cond_destroy) (tds_condition * cond) = detect_cond_destroy;
     163             : int (*tds_raw_cond_signal) (tds_condition * cond) = detect_cond_signal;
     164             : int (*tds_raw_cond_timedwait) (tds_condition * cond, tds_raw_mutex * mtx, int timeout_sec) = detect_cond_timedwait;
     165             : 
     166             : #elif defined(TDS_HAVE_PTHREAD_MUTEX) && !defined(TDS_NO_THREADSAFE)
     167             : 
     168             : #include <freetds/thread.h>
     169             : #include <freetds/time.h>
     170             : 
     171             : /* check if we can use pthread_cond_timedwait_relative_np */
     172             : #undef USE_COND_TIMEDWAIT_RELATIVE
     173             : #if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP) && \
     174             :         (!defined(__ANDROID__) || ((__ANDROID_API__ < 21) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)))
     175             : #define USE_COND_TIMEDWAIT_RELATIVE 1
     176             : #endif
     177             : 
     178             : /* check if we can use clock_gettime */
     179             : #undef USE_CLOCK_GETTIME_IN_COND
     180             : #if !defined(USE_COND_TIMEDWAIT_RELATIVE) && \
     181             :         defined(HAVE_CLOCK_GETTIME) && (defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC))
     182             : #define USE_CLOCK_GETTIME_IN_COND 1
     183             : #endif
     184             : 
     185             : /* check if we can use CLOCK_MONOTONIC for conditions */
     186             : #undef USE_MONOTONIC_CLOCK_IN_COND
     187             : #if defined(USE_CLOCK_GETTIME_IN_COND) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(CLOCK_MONOTONIC)
     188             : #define USE_MONOTONIC_CLOCK_IN_COND 1
     189             : #endif
     190             : 
     191        1906 : int tds_raw_cond_init(tds_condition *cond)
     192             : {
     193             : #ifdef USE_MONOTONIC_CLOCK_IN_COND
     194             :         int res;
     195             :         pthread_condattr_t attr;
     196             : 
     197        1906 :         pthread_condattr_init(&attr);
     198        1906 :         res = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
     199        1906 :         if (!res)
     200        1906 :                 res = pthread_cond_init(cond, &attr);
     201        1906 :         pthread_condattr_destroy(&attr);
     202        1906 :         return res;
     203             : #else
     204             :         return pthread_cond_init(cond, NULL);
     205             : #endif
     206             : }
     207             : 
     208          32 : int tds_raw_cond_timedwait(tds_condition *cond, tds_raw_mutex *mtx, int timeout_sec)
     209             : {
     210             :         struct timespec ts;
     211             : 
     212          32 :         if (timeout_sec <= 0)
     213          16 :                 return tds_raw_cond_wait(cond, mtx);
     214             : 
     215             : #if defined(USE_COND_TIMEDWAIT_RELATIVE)
     216             :         ts.tv_sec = timeout_sec;
     217             :         ts.tv_nsec = 0;
     218             :         return pthread_cond_timedwait_relative_np(cond, mtx, &ts);
     219             : #else
     220             : 
     221             : #  if defined(USE_MONOTONIC_CLOCK_IN_COND)
     222          16 :         clock_gettime(CLOCK_MONOTONIC, &ts);
     223             : #  elif defined(USE_CLOCK_GETTIME_IN_COND)
     224             :         clock_gettime(CLOCK_REALTIME, &ts);
     225             : #  elif defined(HAVE_GETTIMEOFDAY)
     226             :         do {
     227             :                 struct timeval tv;
     228             :                 gettimeofday(&tv, NULL);
     229             :                 ts.tv_sec = tv.tv_sec;
     230             :                 ts.tv_nsec = tv.tv_usec * 1000u;
     231             :         } while(0);
     232             : #  else
     233             : #  error No way to get a proper time!
     234             : #  endif
     235             : 
     236          16 :         ts.tv_sec += timeout_sec;
     237          16 :         return pthread_cond_timedwait(cond, mtx, &ts);
     238             : #endif
     239             : }
     240             : 
     241             : #endif

Generated by: LCOV version 1.13