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

Generated by: LCOV version 1.13