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 | |