| 1 | // Licensed to the .NET Foundation under one or more agreements. | 
|---|
| 2 | // The .NET Foundation licenses this file to you under the MIT license. | 
|---|
| 3 | // See the LICENSE file in the project root for more information. | 
|---|
| 4 |  | 
|---|
| 5 | /*++ | 
|---|
| 6 |  | 
|---|
| 7 |  | 
|---|
| 8 |  | 
|---|
| 9 | Module Name: | 
|---|
| 10 |  | 
|---|
| 11 | cruntime/misc.cpp | 
|---|
| 12 |  | 
|---|
| 13 | Abstract: | 
|---|
| 14 |  | 
|---|
| 15 | Implementation of C runtime functions that don't fit anywhere else. | 
|---|
| 16 |  | 
|---|
| 17 |  | 
|---|
| 18 |  | 
|---|
| 19 | --*/ | 
|---|
| 20 |  | 
|---|
| 21 | #include "pal/thread.hpp" | 
|---|
| 22 | #include "pal/threadsusp.hpp" | 
|---|
| 23 | #include "pal/palinternal.h" | 
|---|
| 24 | #include "pal/dbgmsg.h" | 
|---|
| 25 | #include "pal/misc.h" | 
|---|
| 26 |  | 
|---|
| 27 | #include <errno.h> | 
|---|
| 28 | /* <stdarg.h> needs to be included after "palinternal.h" to avoid name | 
|---|
| 29 | collision for va_start and va_end */ | 
|---|
| 30 | #include <stdarg.h> | 
|---|
| 31 | #include <time.h> | 
|---|
| 32 | #include <limits.h> | 
|---|
| 33 |  | 
|---|
| 34 | #if defined(_AMD64_) || defined(_x86_) | 
|---|
| 35 | #include <xmmintrin.h> | 
|---|
| 36 | #endif // defined(_AMD64_) || defined(_x86_) | 
|---|
| 37 | #if defined(_DEBUG) | 
|---|
| 38 | #include <assert.h> | 
|---|
| 39 | #endif //defined(_DEBUG) | 
|---|
| 40 |  | 
|---|
| 41 | SET_DEFAULT_DEBUG_CHANNEL(CRT); | 
|---|
| 42 |  | 
|---|
| 43 | using namespace CorUnix; | 
|---|
| 44 |  | 
|---|
| 45 | /*++ | 
|---|
| 46 | Function: | 
|---|
| 47 | _gcvt_s | 
|---|
| 48 |  | 
|---|
| 49 | See MSDN doc. | 
|---|
| 50 | --*/ | 
|---|
| 51 | char * | 
|---|
| 52 | __cdecl | 
|---|
| 53 | _gcvt_s( char * buffer, int iSize, double value, int digits ) | 
|---|
| 54 | { | 
|---|
| 55 | PERF_ENTRY(_gcvt); | 
|---|
| 56 | ENTRY( "_gcvt( value:%f digits=%d, buffer=%p )\n", value, digits, buffer ); | 
|---|
| 57 |  | 
|---|
| 58 | if ( !buffer ) | 
|---|
| 59 | { | 
|---|
| 60 | ERROR( "buffer was an invalid pointer.\n"); | 
|---|
| 61 | } | 
|---|
| 62 |  | 
|---|
| 63 | switch ( digits ) | 
|---|
| 64 | { | 
|---|
| 65 | case 7 : | 
|---|
| 66 | /* Fall through */ | 
|---|
| 67 | case 8 : | 
|---|
| 68 | /* Fall through */ | 
|---|
| 69 | case 15 : | 
|---|
| 70 | /* Fall through */ | 
|---|
| 71 | case 17 : | 
|---|
| 72 |  | 
|---|
| 73 | sprintf_s( buffer, iSize, "%.*g", digits, value ); | 
|---|
| 74 | break; | 
|---|
| 75 |  | 
|---|
| 76 | default : | 
|---|
| 77 | ASSERT( "Only the digits 7, 8, 15, and 17 are valid.\n"); | 
|---|
| 78 | *buffer = '\0'; | 
|---|
| 79 | } | 
|---|
| 80 |  | 
|---|
| 81 | LOGEXIT( "_gcvt returns %p (%s)\n", buffer , buffer ); | 
|---|
| 82 | PERF_EXIT(_gcvt); | 
|---|
| 83 | return buffer; | 
|---|
| 84 | } | 
|---|
| 85 |  | 
|---|
| 86 |  | 
|---|
| 87 | /*++ | 
|---|
| 88 | Function : | 
|---|
| 89 |  | 
|---|
| 90 | __iscsym | 
|---|
| 91 |  | 
|---|
| 92 | See MSDN for more details. | 
|---|
| 93 | --*/ | 
|---|
| 94 | int | 
|---|
| 95 | __cdecl | 
|---|
| 96 | __iscsym( int c ) | 
|---|
| 97 | { | 
|---|
| 98 | PERF_ENTRY(__iscsym); | 
|---|
| 99 | ENTRY( "__iscsym( c=%d )\n", c ); | 
|---|
| 100 |  | 
|---|
| 101 | if ( isalnum( c ) || c == '_'  ) | 
|---|
| 102 | { | 
|---|
| 103 | LOGEXIT( "__iscsym returning 1\n"); | 
|---|
| 104 | PERF_EXIT(__iscsym); | 
|---|
| 105 | return 1; | 
|---|
| 106 | } | 
|---|
| 107 |  | 
|---|
| 108 | LOGEXIT( "__iscsym returning 0\n"); | 
|---|
| 109 | PERF_EXIT(__iscsym); | 
|---|
| 110 | return 0; | 
|---|
| 111 | } | 
|---|
| 112 |  | 
|---|
| 113 |  | 
|---|
| 114 | /*++ | 
|---|
| 115 |  | 
|---|
| 116 | Function : | 
|---|
| 117 |  | 
|---|
| 118 | PAL_errno | 
|---|
| 119 |  | 
|---|
| 120 | Returns the address of the errno. | 
|---|
| 121 |  | 
|---|
| 122 | --*/ | 
|---|
| 123 | int * __cdecl PAL_errno( int caller ) | 
|---|
| 124 | { | 
|---|
| 125 | int *retval; | 
|---|
| 126 | PERF_ENTRY(errno); | 
|---|
| 127 | ENTRY( "PAL_errno( void )\n"); | 
|---|
| 128 | retval = (INT*)(&errno); | 
|---|
| 129 | LOGEXIT( "PAL_errno returns %p\n",retval); | 
|---|
| 130 | PERF_EXIT(errno); | 
|---|
| 131 | return retval; | 
|---|
| 132 | } | 
|---|
| 133 |  | 
|---|
| 134 | /*++ | 
|---|
| 135 | Function: | 
|---|
| 136 |  | 
|---|
| 137 | mktime | 
|---|
| 138 |  | 
|---|
| 139 | See MSDN for more details. | 
|---|
| 140 | --*/ | 
|---|
| 141 |  | 
|---|
| 142 | PAL_time_t | 
|---|
| 143 | __cdecl | 
|---|
| 144 | PAL_mktime(struct PAL_tm *tm) | 
|---|
| 145 | { | 
|---|
| 146 | time_t result; | 
|---|
| 147 | struct tm tmpTm; | 
|---|
| 148 |  | 
|---|
| 149 | PERF_ENTRY(mktime); | 
|---|
| 150 | ENTRY( "mktime( tm=%p )\n",tm ); | 
|---|
| 151 |  | 
|---|
| 152 | /*copy the value of Windows struct into BSD struct*/ | 
|---|
| 153 | tmpTm.tm_sec = tm->tm_sec; | 
|---|
| 154 | tmpTm.tm_min = tm->tm_min; | 
|---|
| 155 | tmpTm.tm_hour = tm->tm_hour; | 
|---|
| 156 | tmpTm.tm_mday = tm->tm_mday; | 
|---|
| 157 | tmpTm.tm_mon  = tm->tm_mon; | 
|---|
| 158 | tmpTm.tm_year = tm->tm_year; | 
|---|
| 159 | tmpTm.tm_wday = tm->tm_wday; | 
|---|
| 160 | tmpTm.tm_yday = tm->tm_yday; | 
|---|
| 161 | tmpTm.tm_isdst = tm->tm_isdst; | 
|---|
| 162 |  | 
|---|
| 163 | result = mktime(&tmpTm); | 
|---|
| 164 |  | 
|---|
| 165 | LOGEXIT( "mktime returned %#lx\n",result ); | 
|---|
| 166 | PERF_EXIT(mktime); | 
|---|
| 167 | return result; | 
|---|
| 168 | } | 
|---|
| 169 |  | 
|---|
| 170 | /*++ | 
|---|
| 171 | Function: | 
|---|
| 172 |  | 
|---|
| 173 | rand | 
|---|
| 174 |  | 
|---|
| 175 | The RAND_MAX value can vary by platform. | 
|---|
| 176 |  | 
|---|
| 177 | See MSDN for more details. | 
|---|
| 178 | --*/ | 
|---|
| 179 | int | 
|---|
| 180 | __cdecl | 
|---|
| 181 | PAL_rand(void) | 
|---|
| 182 | { | 
|---|
| 183 | int ret; | 
|---|
| 184 | PERF_ENTRY(rand); | 
|---|
| 185 | ENTRY( "rand(void)\n"); | 
|---|
| 186 |  | 
|---|
| 187 | ret = (rand() % (PAL_RAND_MAX + 1)); | 
|---|
| 188 |  | 
|---|
| 189 | LOGEXIT( "rand() returning %d\n", ret); | 
|---|
| 190 | PERF_EXIT(rand); | 
|---|
| 191 | return ret; | 
|---|
| 192 | } | 
|---|
| 193 |  | 
|---|
| 194 |  | 
|---|
| 195 | /*++ | 
|---|
| 196 | Function: | 
|---|
| 197 |  | 
|---|
| 198 | time | 
|---|
| 199 |  | 
|---|
| 200 | See MSDN for more details. | 
|---|
| 201 | --*/ | 
|---|
| 202 | PAL_time_t | 
|---|
| 203 | __cdecl | 
|---|
| 204 | PAL_time(PAL_time_t *tloc) | 
|---|
| 205 | { | 
|---|
| 206 | time_t result; | 
|---|
| 207 |  | 
|---|
| 208 | PERF_ENTRY(time); | 
|---|
| 209 | ENTRY( "time( tloc=%p )\n",tloc ); | 
|---|
| 210 |  | 
|---|
| 211 | result = time(tloc); | 
|---|
| 212 |  | 
|---|
| 213 | LOGEXIT( "time returning %#lx\n",result ); | 
|---|
| 214 | PERF_EXIT(time); | 
|---|
| 215 | return result; | 
|---|
| 216 | } | 
|---|
| 217 |  | 
|---|
| 218 |  | 
|---|
| 219 | PALIMPORT | 
|---|
| 220 | void __cdecl | 
|---|
| 221 | PAL_qsort(void *base, size_t nmemb, size_t size, | 
|---|
| 222 | int (__cdecl *compar )(const void *, const void *)) | 
|---|
| 223 | { | 
|---|
| 224 | PERF_ENTRY(qsort); | 
|---|
| 225 | ENTRY( "qsort(base=%p, nmemb=%lu, size=%lu, compar=%p\n", | 
|---|
| 226 | base,(unsigned long) nmemb,(unsigned long) size, compar); | 
|---|
| 227 |  | 
|---|
| 228 | /* reset ENTRY nesting level back to zero, qsort will invoke app-defined | 
|---|
| 229 | callbacks and we want their entry traces... */ | 
|---|
| 230 | #if _ENABLE_DEBUG_MESSAGES_ | 
|---|
| 231 | { | 
|---|
| 232 | int old_level; | 
|---|
| 233 | old_level = DBG_change_entrylevel(0); | 
|---|
| 234 | #endif /* _ENABLE_DEBUG_MESSAGES_ */ | 
|---|
| 235 |  | 
|---|
| 236 | qsort(base,nmemb,size,compar); | 
|---|
| 237 |  | 
|---|
| 238 | /* ...and set nesting level back to what it was */ | 
|---|
| 239 | #if _ENABLE_DEBUG_MESSAGES_ | 
|---|
| 240 | DBG_change_entrylevel(old_level); | 
|---|
| 241 | } | 
|---|
| 242 | #endif /* _ENABLE_DEBUG_MESSAGES_ */ | 
|---|
| 243 |  | 
|---|
| 244 | LOGEXIT( "qsort returns\n"); | 
|---|
| 245 | PERF_EXIT(qsort); | 
|---|
| 246 | } | 
|---|
| 247 |  | 
|---|
| 248 | PALIMPORT | 
|---|
| 249 | void * __cdecl | 
|---|
| 250 | PAL_bsearch(const void *key, const void *base, size_t nmemb, size_t size, | 
|---|
| 251 | int (__cdecl *compar)(const void *, const void *)) | 
|---|
| 252 | { | 
|---|
| 253 | void *retval; | 
|---|
| 254 |  | 
|---|
| 255 | PERF_ENTRY(bsearch); | 
|---|
| 256 | ENTRY( "bsearch(key=%p, base=%p, nmemb=%lu, size=%lu, compar=%p\n", | 
|---|
| 257 | key, base, (unsigned long) nmemb, (unsigned long) size, compar); | 
|---|
| 258 |  | 
|---|
| 259 | /* reset ENTRY nesting level back to zero, bsearch will invoke app-defined | 
|---|
| 260 | callbacks and we want their entry traces... */ | 
|---|
| 261 | #if _ENABLE_DEBUG_MESSAGES_ | 
|---|
| 262 | { | 
|---|
| 263 | int old_level; | 
|---|
| 264 | old_level = DBG_change_entrylevel(0); | 
|---|
| 265 | #endif /* _ENABLE_DEBUG_MESSAGES_ */ | 
|---|
| 266 |  | 
|---|
| 267 | retval = bsearch(key,base,nmemb,size,compar); | 
|---|
| 268 |  | 
|---|
| 269 | /* ...and set nesting level back to what it was */ | 
|---|
| 270 | #if _ENABLE_DEBUG_MESSAGES_ | 
|---|
| 271 | DBG_change_entrylevel(old_level); | 
|---|
| 272 | } | 
|---|
| 273 | #endif /* _ENABLE_DEBUG_MESSAGES_ */ | 
|---|
| 274 |  | 
|---|
| 275 | LOGEXIT( "bsearch returns %p\n",retval); | 
|---|
| 276 | PERF_EXIT(bsearch); | 
|---|
| 277 | return retval; | 
|---|
| 278 | } | 
|---|
| 279 |  | 
|---|
| 280 | #ifdef _AMD64_ | 
|---|
| 281 |  | 
|---|
| 282 | PALIMPORT | 
|---|
| 283 | unsigned int PAL__mm_getcsr(void) | 
|---|
| 284 | { | 
|---|
| 285 | return _mm_getcsr(); | 
|---|
| 286 | } | 
|---|
| 287 |  | 
|---|
| 288 | PALIMPORT | 
|---|
| 289 | void PAL__mm_setcsr(unsigned int i) | 
|---|
| 290 | { | 
|---|
| 291 | _mm_setcsr(i); | 
|---|
| 292 | } | 
|---|
| 293 |  | 
|---|
| 294 | #endif // _AMD64_ | 
|---|
| 295 |  | 
|---|
| 296 | /*++ | 
|---|
| 297 | Function: | 
|---|
| 298 | PAL_memcpy | 
|---|
| 299 |  | 
|---|
| 300 | Overlapping buffer-safe version of memcpy. | 
|---|
| 301 | See MSDN doc for memcpy | 
|---|
| 302 | --*/ | 
|---|
| 303 | EXTERN_C | 
|---|
| 304 | PALIMPORT | 
|---|
| 305 | void *PAL_memcpy (void *dest, const void *src, size_t count) | 
|---|
| 306 | { | 
|---|
| 307 | UINT_PTR x = (UINT_PTR)dest, y = (UINT_PTR)src; | 
|---|
| 308 | _ASSERTE((x + count <= y) || (y + count <= x)); | 
|---|
| 309 |  | 
|---|
| 310 | void *ret; | 
|---|
| 311 | #undef memcpy | 
|---|
| 312 | ret = memcpy(dest, src, count); | 
|---|
| 313 | return ret; | 
|---|
| 314 | } | 
|---|
| 315 |  | 
|---|