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