Home | History | Annotate | Line # | Download | only in crypto
      1 /*
      2  * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #include <openssl/crypto.h>
     11 #include "internal/e_os.h"
     12 #include "internal/time.h"
     13 
     14 /* system-specific variants defining OSSL_sleep() */
     15 #if (defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__)) && !defined(OPENSSL_USE_SLEEP_BUSYLOOP)
     16 
     17 #if defined(OPENSSL_USE_USLEEP) \
     18     || defined(__DJGPP__)       \
     19     || (defined(__TANDEM) && defined(_REENTRANT))
     20 
     21 /*
     22  * usleep() was made obsolete by POSIX.1-2008, and nanosleep()
     23  * should be used instead.  However, nanosleep() isn't implemented
     24  * on the platforms given above, so we still use it for those.
     25  * Also, OPENSSL_USE_USLEEP can be defined to enable the use of
     26  * usleep, if it turns out that nanosleep() is unavailable.
     27  */
     28 
     29 #include <unistd.h>
     30 static void ossl_sleep_millis(uint64_t millis)
     31 {
     32     unsigned int s = (unsigned int)(millis / 1000);
     33     unsigned int us = (unsigned int)((millis % 1000) * 1000);
     34 
     35     if (s > 0)
     36         sleep(s);
     37     /*
     38      * On NonStop with the PUT thread model, thread context switch is
     39      * cooperative, with usleep() being a "natural" context switch point.
     40      * We avoid checking us > 0 here, to allow that context switch to
     41      * happen.
     42      */
     43     usleep(us);
     44 }
     45 
     46 #elif defined(__TANDEM) && !defined(_REENTRANT)
     47 
     48 #include <cextdecs.h(PROCESS_DELAY_)>
     49 static void ossl_sleep_millis(uint64_t millis)
     50 {
     51     /* HPNS does not support usleep for non threaded apps */
     52     PROCESS_DELAY_(millis * 1000);
     53 }
     54 
     55 #else
     56 
     57 /* nanosleep is defined by POSIX.1-2001 */
     58 #include <time.h>
     59 static void ossl_sleep_millis(uint64_t millis)
     60 {
     61     struct timespec ts;
     62 
     63     ts.tv_sec = (long int)(millis / 1000);
     64     ts.tv_nsec = (long int)(millis % 1000) * 1000000ul;
     65     nanosleep(&ts, NULL);
     66 }
     67 
     68 #endif
     69 #elif defined(_WIN32) && !defined(OPENSSL_SYS_UEFI)
     70 #include <windows.h>
     71 
     72 static void ossl_sleep_millis(uint64_t millis)
     73 {
     74     /*
     75      * Windows' Sleep() takes a DWORD argument, which is smaller than
     76      * a uint64_t, so we need to limit it to 49 days, which should be enough.
     77      */
     78     DWORD limited_millis = (DWORD)-1;
     79 
     80     if (millis < limited_millis)
     81         limited_millis = (DWORD)millis;
     82     Sleep(limited_millis);
     83 }
     84 
     85 #else
     86 /* Fallback to a busy wait */
     87 #define USE_SLEEP_SECS
     88 
     89 static void ossl_sleep_secs(uint64_t secs)
     90 {
     91     /*
     92      * sleep() takes an unsigned int argument, which is smaller than
     93      * a uint64_t, so it needs to be limited to 136 years which
     94      * should be enough even for Sleeping Beauty.
     95      */
     96     unsigned int limited_secs = UINT_MAX;
     97 
     98     if (secs < limited_secs)
     99         limited_secs = (unsigned int)secs;
    100     sleep(limited_secs);
    101 }
    102 
    103 static void ossl_sleep_millis(uint64_t millis)
    104 {
    105     const OSSL_TIME finish
    106         = ossl_time_add(ossl_time_now(), ossl_ms2time(millis));
    107 
    108     while (ossl_time_compare(ossl_time_now(), finish) < 0)
    109         /* busy wait */;
    110 }
    111 #endif /* defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__) */
    112 
    113 void OSSL_sleep(uint64_t millis)
    114 {
    115     OSSL_TIME now = ossl_time_now();
    116     OSSL_TIME finish = ossl_time_add(now, ossl_ms2time(millis));
    117     uint64_t left = millis;
    118 
    119 #if defined(USE_SLEEP_SECS)
    120     do {
    121         ossl_sleep_secs(left / 1000);
    122         now = ossl_time_now();
    123         left = ossl_time2ms(ossl_time_subtract(finish, now));
    124     } while (ossl_time_compare(now, finish) < 0 && left > 1000);
    125 
    126     if (ossl_time_compare(now, finish) >= 0)
    127         return;
    128 #endif
    129 
    130     do {
    131         ossl_sleep_millis(left);
    132         now = ossl_time_now();
    133         left = ossl_time2ms(ossl_time_subtract(finish, now));
    134     } while (ossl_time_compare(now, finish) < 0);
    135 }
    136