1 // SoftEther VPN Source Code - Developer Edition Master Branch
2 // Mayaqua Kernel
3
4
5 // Kernel.c
6 // System service processing routine
7
8 #include "Kernel.h"
9
10 #include "Encrypt.h"
11 #include "Internat.h"
12 #include "Mayaqua.h"
13 #include "Memory.h"
14 #include "Microsoft.h"
15 #include "Object.h"
16 #include "Str.h"
17 #include "Table.h"
18 #include "Tracking.h"
19 #include "Unix.h"
20 #include "Win32.h"
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25
26 #ifdef OS_UNIX
27 #include <sys/time.h>
28 #endif
29
30 #ifndef TM_YEAR_MAX
31 #define TM_YEAR_MAX 2106
32 #endif
33 #ifndef TM_MON_MAX
34 #define TM_MON_MAX 1
35 #endif
36 #ifndef TM_MDAY_MAX
37 #define TM_MDAY_MAX 7
38 #endif
39 #ifndef TM_HOUR_MAX
40 #define TM_HOUR_MAX 6
41 #endif
42 #ifndef TM_MIN_MAX
43 #define TM_MIN_MAX 28
44 #endif
45 #ifndef TM_SEC_MAX
46 #define TM_SEC_MAX 14
47 #endif
48
49 #define ADJUST_TM(tm_member, tm_carry, modulus) \
50 if ((tm_member) < 0){ \
51 tm_carry -= (1 - ((tm_member)+1) / (modulus)); \
52 tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \
53 } else if ((tm_member) >= (modulus)) { \
54 tm_carry += (tm_member) / (modulus); \
55 tm_member = (tm_member) % (modulus); \
56 }
57 #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
58 #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
59 #define leapday(m, y) ((m) == 1 && leap (y))
60 #define monthlen(m, y) (ydays[(m)+1] - ydays[m] + leapday (m, y))
61 static int ydays[] =
62 {
63 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
64 };
65
66 static UINT current_num_thread = 0;
67 static UINT cached_number_of_cpus = 0;
68
69
70
71 static wchar_t *default_locale_str =
72 L"- - $ : : $ Sun Mon Tue Wed Thu Fri Sat : : : $ (None)";
73
74
75 static LOCALE current_locale;
76 LOCK *tick_manual_lock = NULL;
77
78 #define MONSPERYEAR 12
79 #define DAYSPERNYEAR 365
80 #define DAYSPERLYEAR 366
81 #define SECSPERMIN 60
82 #define SECSPERHOUR (60*60)
83 #define SECSPERDAY (24*60*60)
84 #define DAYSPERWEEK 7
85 #define TM_SUNDAY 0
86 #define TM_MONDAY 1
87 #define TM_TUESDAY 2
88 #define TM_WEDNESDAY 3
89 #define TM_THURSDAY 4
90 #define TM_FRIDAY 5
91 #define TM_SATURDAY 6
92
93 #define TM_YEAR_BASE 1900
94
95 #define EPOCH_YEAR 1970
96 #define EPOCH_WDAY TM_THURSDAY
97
98 #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
99
100 static const int mon_lengths[2][MONSPERYEAR] = {
101 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
102 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
103 };
104
105 static const int year_lengths[2] = {
106 DAYSPERNYEAR, DAYSPERLYEAR
107 };
108
109
110 /*
111 * Taken from FreeBSD src / lib / libc / stdtime / localtime.c 1.43 revision.
112 * localtime.c 7.78.
113 * tzfile.h 1.8
114 * adapted to be replacement gmtime_r.
115 */
116 static void
c_timesub(timep,offset,tmp)117 c_timesub(timep, offset, tmp)
118 const time_64t * const timep;
119 const long offset;
120 struct tm * const tmp;
121 {
122 INT64 days;
123 INT64 rem;
124 INT64 y;
125 int yleap;
126 const int * ip;
127
128 days = *timep / SECSPERDAY;
129 rem = *timep % SECSPERDAY;
130 rem += (offset);
131 while (rem < 0) {
132 rem += SECSPERDAY;
133 --days;
134 }
135 while (rem >= SECSPERDAY) {
136 rem -= SECSPERDAY;
137 ++days;
138 }
139 tmp->tm_hour = (int) (rem / SECSPERHOUR);
140 rem = rem % SECSPERHOUR;
141 tmp->tm_min = (int) (rem / SECSPERMIN);
142 /*
143 ** A positive leap second requires a special
144 ** representation. This uses "... ??:59:60" et seq.
145 */
146 tmp->tm_sec = (int) (rem % SECSPERMIN) ;
147 tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
148 if (tmp->tm_wday < 0)
149 tmp->tm_wday += DAYSPERWEEK;
150 y = EPOCH_YEAR;
151 #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
152 while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
153 INT64 newy;
154
155 newy = y + days / DAYSPERNYEAR;
156 if (days < 0)
157 --newy;
158 days -= (newy - y) * DAYSPERNYEAR +
159 LEAPS_THRU_END_OF(newy - 1) -
160 LEAPS_THRU_END_OF(y - 1);
161 y = newy;
162 }
163 tmp->tm_year = (int)(y - TM_YEAR_BASE);
164 tmp->tm_yday = (int) days;
165 ip = mon_lengths[yleap];
166 for (tmp->tm_mon = 0; days >= (INT64) ip[tmp->tm_mon]; ++(tmp->tm_mon))
167 days = days - (INT64) ip[tmp->tm_mon];
168 tmp->tm_mday = (int) (days + 1);
169 tmp->tm_isdst = 0;
170 }
171
172 /*
173 * Re-entrant version of gmtime.
174 */
c_gmtime_r(const time_64t * timep,struct tm * tm)175 struct tm * c_gmtime_r(const time_64t* timep, struct tm *tm)
176 {
177 c_timesub(timep, 0L, tm);
178 return tm;
179 }
180
181 // Get the real-time system timer
TickRealtime()182 UINT TickRealtime()
183 {
184 #if defined(OS_WIN32) || defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) || defined(CLOCK_HIGHRES) || defined(UNIX_MACOS)
185 return Tick() + 1;
186 #else
187 return TickRealtimeManual() + 1;
188 #endif
189 }
190
191 #ifndef OS_WIN32
192
193 static UINT64 last_manual_tick = 0;
194 static UINT64 manual_tick_add_value = 0;
195
196 // For systems which not have clock_gettime (such as MacOS X)
TickRealtimeManual()197 UINT TickRealtimeManual()
198 {
199 UINT64 ret;
200 Lock(tick_manual_lock);
201 {
202 ret = TickGetRealtimeTickValue64();
203
204 if (last_manual_tick != 0 && (last_manual_tick > ret))
205 {
206 manual_tick_add_value += (last_manual_tick - ret);
207 }
208
209 last_manual_tick = ret;
210 }
211 Unlock(tick_manual_lock);
212
213 return (UINT)(ret + manual_tick_add_value);
214 }
215
216 // Returns a appropriate value from the current time
TickGetRealtimeTickValue64()217 UINT64 TickGetRealtimeTickValue64()
218 {
219 struct timeval tv;
220 struct timezone tz;
221 UINT64 ret;
222
223 memset(&tv, 0, sizeof(tv));
224 memset(&tz, 0, sizeof(tz));
225
226 gettimeofday(&tv, &tz);
227
228 if (sizeof(tv.tv_sec) != 4)
229 {
230 ret = (UINT64)tv.tv_sec * 1000ULL + (UINT64)tv.tv_usec / 1000ULL;
231 }
232 else
233 {
234 ret = (UINT64)((UINT64)((UINT)tv.tv_sec)) * 1000ULL + (UINT64)tv.tv_usec / 1000ULL;
235 }
236
237 return ret;
238 }
239
240 #endif // OS_WIN32
241
242 // Get the number of CPUs
GetNumberOfCpu()243 UINT GetNumberOfCpu()
244 {
245 UINT ret = 0;
246
247 if (cached_number_of_cpus == 0)
248 {
249 UINT i = 0;
250
251 #ifdef OS_WIN32
252 i = Win32GetNumberOfCpuInner();
253 #else // OS_WIN32
254 i = UnixGetNumberOfCpuInner();
255 #endif // OS_WIN32
256
257 if (i == 0)
258 {
259 i = 8;
260 }
261
262 cached_number_of_cpus = i;
263 }
264
265 ret = cached_number_of_cpus;
266
267 if (ret == 0)
268 {
269 ret = 1;
270 }
271 if (ret > 128)
272 {
273 ret = 128;
274 }
275
276 return ret;
277 }
278
279 // Creating a thread list
NewThreadList()280 LIST *NewThreadList()
281 {
282 LIST *o = NewList(NULL);
283
284 return o;
285 }
286
287 // Add the thread to the thread list
AddThreadToThreadList(LIST * o,THREAD * t)288 void AddThreadToThreadList(LIST *o, THREAD *t)
289 {
290 // Validate arguments
291 if (o == NULL || t == NULL)
292 {
293 return;
294 }
295
296 LockList(o);
297 {
298 if (IsInList(o, t) == false)
299 {
300 AddRef(t->ref);
301
302 Add(o, t);
303 }
304 }
305 UnlockList(o);
306 }
307
308 // Maintain thread list
MaintainThreadList(LIST * o)309 void MaintainThreadList(LIST *o)
310 {
311 UINT i;
312 LIST *delete_list = NULL;
313 // Validate arguments
314 if (o == NULL)
315 {
316 return;
317 }
318
319 LockList(o);
320 {
321 for (i = 0;i < LIST_NUM(o);i++)
322 {
323 THREAD *t = LIST_DATA(o, i);
324
325 if (t->Stopped)
326 {
327 if (delete_list == NULL)
328 {
329 delete_list = NewListFast(NULL);
330 }
331
332 Add(delete_list, t);
333 }
334 }
335
336 if (delete_list != NULL)
337 {
338 for (i = 0;i < LIST_NUM(delete_list);i++)
339 {
340 THREAD *t = LIST_DATA(delete_list, i);
341
342 ReleaseThread(t);
343
344 Delete(o, t);
345 }
346
347 ReleaseList(delete_list);
348 }
349 }
350 UnlockList(o);
351 }
352
353 // Stop all the threads in the thread list
StopThreadList(LIST * o)354 void StopThreadList(LIST *o)
355 {
356 UINT i;
357 // Validate arguments
358 if (o == NULL)
359 {
360 return;
361 }
362
363 LockList(o);
364 {
365 for (i = 0;i < LIST_NUM(o);i++)
366 {
367 THREAD *t = LIST_DATA(o, i);
368
369 WaitThread(t, INFINITE);
370 }
371 }
372 UnlockList(o);
373 }
374
375 // Release the thread list
FreeThreadList(LIST * o)376 void FreeThreadList(LIST *o)
377 {
378 UINT i;
379 // Validate arguments
380 if (o == NULL)
381 {
382 return;
383 }
384
385 LockList(o);
386 {
387 for (i = 0;i < LIST_NUM(o);i++)
388 {
389 THREAD *t = LIST_DATA(o, i);
390
391 WaitThread(t, INFINITE);
392
393 ReleaseThread(t);
394 }
395
396 DeleteAll(o);
397 }
398 UnlockList(o);
399
400 ReleaseList(o);
401 }
402
403 // Get the home directory
GetHomeDirW(wchar_t * path,UINT size)404 void GetHomeDirW(wchar_t *path, UINT size)
405 {
406 // Validate arguments
407 if (path == NULL)
408 {
409 return;
410 }
411
412 if (GetEnvW(L"HOME", path, size) == false)
413 {
414 wchar_t drive[MAX_SIZE];
415 wchar_t hpath[MAX_SIZE];
416 if (GetEnvW(L"HOMEDRIVE", drive, sizeof(drive)) &&
417 GetEnvW(L"HOMEPATH", hpath, sizeof(hpath)))
418 {
419 UniFormat(path, size, L"%s%s", drive, hpath);
420 }
421 else
422 {
423 #ifdef OS_WIN32
424 Win32GetCurrentDirW(path, size);
425 #else // OS_WIN32
426 UnixGetCurrentDirW(path, size);
427 #endif // OS_WIN32
428 }
429 }
430 }
431
432 // Get the environment variable string
GetEnv(char * name,char * data,UINT size)433 bool GetEnv(char *name, char *data, UINT size)
434 {
435 char *ret;
436 // Validate arguments
437 if (name == NULL || data == NULL)
438 {
439 return false;
440 }
441
442 StrCpy(data, size, "");
443
444 ret = getenv(name);
445 if (ret == NULL)
446 {
447 return false;
448 }
449
450 StrCpy(data, size, ret);
451
452 return true;
453 }
GetEnvW(wchar_t * name,wchar_t * data,UINT size)454 bool GetEnvW(wchar_t *name, wchar_t *data, UINT size)
455 {
456 #ifdef OS_WIN32
457 return GetEnvW_ForWin32(name, data, size);
458 #else // OS_WIN32
459 return GetEnvW_ForUnix(name, data, size);
460 #endif // OS_WIN32
461 }
462
463 #ifdef OS_WIN32
GetEnvW_ForWin32(wchar_t * name,wchar_t * data,UINT size)464 bool GetEnvW_ForWin32(wchar_t *name, wchar_t *data, UINT size)
465 {
466 wchar_t *ret;
467 // Validate arguments
468 if (name == NULL || data == NULL)
469 {
470 return false;
471 }
472
473 if (IsNt() == false)
474 {
475 bool ret;
476 char *name_a = CopyUniToStr(name);
477 char data_a[MAX_SIZE];
478
479 ret = GetEnv(name_a, data_a, sizeof(data_a));
480
481 if (ret)
482 {
483 StrToUni(data, size, data_a);
484 }
485
486 Free(name_a);
487
488 return ret;
489 }
490
491 UniStrCpy(data, size, L"");
492
493 ret = _wgetenv(name);
494 if (ret == NULL)
495 {
496 return false;
497 }
498
499 UniStrCpy(data, size, ret);
500
501 return true;
502 }
503
504 #endif // OS_WIN32
505
506 #ifdef OS_UNIX
507
GetEnvW_ForUnix(wchar_t * name,wchar_t * data,UINT size)508 bool GetEnvW_ForUnix(wchar_t *name, wchar_t *data, UINT size)
509 {
510 char *name_a;
511 bool ret;
512 char data_a[MAX_SIZE];
513 // Validate arguments
514 if (name == NULL || data == NULL)
515 {
516 return false;
517 }
518
519 name_a = CopyUniToUtf(name);
520
521 ret = GetEnv(name_a, data_a, sizeof(data_a));
522
523 if (ret)
524 {
525 UtfToUni(data, size, data_a);
526 }
527
528 Free(name_a);
529
530 return ret;
531 }
532
533 #endif // OS_UNIX
534
535 // Get the memory information
GetMemInfo(MEMINFO * info)536 void GetMemInfo(MEMINFO *info)
537 {
538 OSGetMemInfo(info);
539 }
540
541 // Start the single-instance
NewSingleInstance(char * instance_name)542 INSTANCE *NewSingleInstance(char *instance_name)
543 {
544 return NewSingleInstanceEx(instance_name, false);
545 }
NewSingleInstanceEx(char * instance_name,bool user_local)546 INSTANCE *NewSingleInstanceEx(char *instance_name, bool user_local)
547 {
548 char name[MAX_SIZE];
549 INSTANCE *ret;
550 void *data;
551
552 if (instance_name != NULL)
553 {
554 if (user_local == false)
555 {
556 HashInstanceName(name, sizeof(name), instance_name);
557 }
558 else
559 {
560 HashInstanceNameLocal(name, sizeof(name), instance_name);
561 }
562
563 data = OSNewSingleInstance(name);
564 }
565 else
566 {
567 data = OSNewSingleInstance(NULL);
568 }
569
570 if (data == NULL)
571 {
572 return NULL;
573 }
574
575 ret = ZeroMalloc(sizeof(INSTANCE));
576 if (instance_name != NULL)
577 {
578 ret->Name = CopyStr(instance_name);
579 }
580
581 ret->pData = data;
582
583 return ret;
584 }
585
586 // Release of single instance
FreeSingleInstance(INSTANCE * inst)587 void FreeSingleInstance(INSTANCE *inst)
588 {
589 // Validate arguments
590 if (inst == NULL)
591 {
592 return;
593 }
594
595 OSFreeSingleInstance(inst->pData);
596
597 if (inst->Name != NULL)
598 {
599 Free(inst->Name);
600 }
601 Free(inst);
602 }
603
604 // Hashing the instance name
HashInstanceName(char * name,UINT size,char * instance_name)605 void HashInstanceName(char *name, UINT size, char *instance_name)
606 {
607 char tmp[MAX_SIZE];
608 UCHAR hash[SHA1_SIZE];
609 char key[11];
610 // Validate arguments
611 if (name == NULL || instance_name == NULL)
612 {
613 return;
614 }
615
616 StrCpy(tmp, sizeof(tmp), instance_name);
617 Trim(tmp);
618 StrUpper(tmp);
619
620 Sha0(hash, tmp, StrLen(tmp));
621 BinToStr(key, sizeof(key), hash, 5);
622 key[10] = 0;
623
624 Format(name, size, "VPN-%s", key);
625
626 StrCpy(tmp, sizeof(tmp), name);
627 Format(name, size, "Global\\%s", tmp);
628 }
HashInstanceNameLocal(char * name,UINT size,char * instance_name)629 void HashInstanceNameLocal(char *name, UINT size, char *instance_name)
630 {
631 char tmp[MAX_SIZE];
632 UCHAR hash[SHA1_SIZE];
633 char key[11];
634 // Validate arguments
635 if (name == NULL || instance_name == NULL)
636 {
637 return;
638 }
639
640 StrCpy(tmp, sizeof(tmp), instance_name);
641 Trim(tmp);
642 StrUpper(tmp);
643
644 Sha0(hash, tmp, StrLen(tmp));
645 BinToStr(key, sizeof(key), hash, 5);
646 key[10] = 0;
647
648 Format(name, size, "VPN-%s", key);
649
650 StrCpy(tmp, sizeof(tmp), name);
651 Format(name, size, "Local\\%s", tmp);
652 }
653
654 // Run the process
Run(char * filename,char * arg,bool hide,bool wait)655 bool Run(char *filename, char *arg, bool hide, bool wait)
656 {
657 // Validate arguments
658 if (filename == NULL)
659 {
660 return false;
661 }
662
663 return OSRun(filename, arg, hide, wait);
664 }
RunW(wchar_t * filename,wchar_t * arg,bool hide,bool wait)665 bool RunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait)
666 {
667 // Validate arguments
668 if (filename == NULL)
669 {
670 return false;
671 }
672
673 return OSRunW(filename, arg, hide, wait);
674 }
675
676 // Date and time related functions
GetDateTimeStr64Uni(wchar_t * str,UINT size,UINT64 sec64)677 void GetDateTimeStr64Uni(wchar_t *str, UINT size, UINT64 sec64)
678 {
679 char tmp[MAX_SIZE];
680 if (str == NULL)
681 {
682 return;
683 }
684
685 GetDateTimeStr64(tmp, sizeof(tmp), sec64);
686 StrToUni(str, size, tmp);
687 }
GetDateTimeStr64(char * str,UINT size,UINT64 sec64)688 void GetDateTimeStr64(char *str, UINT size, UINT64 sec64)
689 {
690 SYSTEMTIME st;
691 UINT64ToSystem(&st, sec64);
692 GetDateTimeStr(str, size, &st);
693 }
GetDateTimeStrMilli64(char * str,UINT size,UINT64 sec64)694 void GetDateTimeStrMilli64(char *str, UINT size, UINT64 sec64)
695 {
696 SYSTEMTIME st;
697 UINT64ToSystem(&st, sec64);
698 GetDateTimeStrMilli(str, size, &st);
699 }
GetDateTimeStrMilli64ForFileName(char * str,UINT size,UINT64 sec64)700 void GetDateTimeStrMilli64ForFileName(char *str, UINT size, UINT64 sec64)
701 {
702 SYSTEMTIME st;
703 UINT64ToSystem(&st, sec64);
704 GetDateTimeStrMilliForFileName(str, size, &st);
705 }
GetDateTimeStrMilliForFileName(char * str,UINT size,SYSTEMTIME * tm)706 void GetDateTimeStrMilliForFileName(char *str, UINT size, SYSTEMTIME *tm)
707 {
708 Format(str, size, "%04u%02u%02u_%02u%02u%02u",
709 tm->wYear, tm->wMonth, tm->wDay, tm->wHour, tm->wMinute, tm->wSecond);
710 }
GetDateStr64(char * str,UINT size,UINT64 sec64)711 void GetDateStr64(char *str, UINT size, UINT64 sec64)
712 {
713 SYSTEMTIME st;
714 if (sec64 == 0)
715 {
716 StrCpy(str, size, "(Unknown)");
717 return;
718 }
719 UINT64ToSystem(&st, sec64);
720 GetDateStr(str, size, &st);
721 }
GetDateTimeStrEx64(wchar_t * str,UINT size,UINT64 sec64,LOCALE * locale)722 void GetDateTimeStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)
723 {
724 SYSTEMTIME st;
725 if (locale == NULL)
726 {
727 locale = ¤t_locale;
728 }
729 if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
730 {
731 UniStrCpy(str, size, locale->Unknown);
732 return;
733 }
734 UINT64ToSystem(&st, sec64);
735 GetDateTimeStrEx(str, size, &st, locale);
736 }
GetDateStrEx64(wchar_t * str,UINT size,UINT64 sec64,LOCALE * locale)737 void GetDateStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)
738 {
739 SYSTEMTIME st;
740 if (locale == NULL)
741 {
742 locale = ¤t_locale;
743 }
744 if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
745 {
746 UniStrCpy(str, size, locale->Unknown);
747 return;
748 }
749 UINT64ToSystem(&st, sec64);
750 GetDateStrEx(str, size, &st, locale);
751 }
GetTimeStrMilli64(char * str,UINT size,UINT64 sec64)752 void GetTimeStrMilli64(char *str, UINT size, UINT64 sec64)
753 {
754 SYSTEMTIME st;
755 if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
756 {
757 StrCpy(str, size, "(Unknown)");
758 return;
759 }
760 UINT64ToSystem(&st, sec64);
761 GetTimeStrMilli(str, size, &st);
762 }
763
764 // Convert to a time to be used safely in the current POSIX implementation
SafeTime64(UINT64 sec64)765 UINT64 SafeTime64(UINT64 sec64)
766 {
767 return MAKESURE(sec64, 0, 4102243323123ULL);
768 }
769
770 // Thread pool
771 static SK *thread_pool = NULL;
772 static COUNTER *thread_count = NULL;
773
774 // Initialization of thread pool
InitThreading()775 void InitThreading()
776 {
777 thread_pool = NewSk();
778 thread_count = NewCounter();
779 }
780
781 // Release of thread pool
FreeThreading()782 void FreeThreading()
783 {
784 while (true)
785 {
786 if (Count(thread_count) == 0)
787 {
788 break;
789 }
790
791 SleepThread(25);
792 }
793
794 while (true)
795 {
796 THREAD_POOL_DATA *pd;
797 THREAD *t = Pop(thread_pool);
798
799 if (t == NULL)
800 {
801 break;
802 }
803
804 pd = (THREAD_POOL_DATA *)t->param;
805
806 pd->ThreadProc = NULL;
807 Set(pd->Event);
808
809 WaitThreadInternal(t);
810
811 pd = (THREAD_POOL_DATA *)t->param;
812 ReleaseEvent(pd->Event);
813 ReleaseEvent(pd->InitFinishEvent);
814
815 ReleaseThreadInternal(t);
816
817 Free(pd);
818 }
819
820 ReleaseSk(thread_pool);
821
822 DeleteCounter(thread_count);
823 thread_count = NULL;
824 }
825
826 // Thread pool procedure
ThreadPoolProc(THREAD * t,void * param)827 void ThreadPoolProc(THREAD *t, void *param)
828 {
829 THREAD_POOL_DATA *pd;
830 // Validate arguments
831 if (t == NULL)
832 {
833 return;
834 }
835
836 pd = (THREAD_POOL_DATA *)param;
837
838 NoticeThreadInitInternal(t);
839
840 while (true)
841 {
842 THREAD *thread;
843 UINT i, num;
844 EVENT **ee;
845
846 // Wait for the next job
847 Wait(pd->Event, INFINITE);
848
849 if (pd->ThreadProc == NULL)
850 {
851 // Stop the pool thread
852 break;
853 }
854
855 thread = pd->Thread;
856 thread->ThreadId = ThreadId();
857
858 // Initialization is completed
859 Set(pd->InitFinishEvent);
860
861 // Set the thread name
862 if (thread->Name != NULL)
863 {
864 SetThreadName(thread->ThreadId, thread->Name, thread->param);
865 }
866 else
867 {
868 SetThreadName(thread->ThreadId, "Unknown", 0);
869 }
870
871 // Run the thread procedure
872 pd->ThreadProc(pd->Thread, thread->param);
873
874 // Set the thread name
875 SetThreadName(thread->ThreadId, NULL, 0);
876
877 pd->Thread->Stopped = true;
878
879 thread->PoolHalting = true;
880
881 // Set the waiting event list
882 LockList(thread->PoolWaitList);
883 {
884 num = LIST_NUM(thread->PoolWaitList);
885 ee = ToArray(thread->PoolWaitList);
886
887 DeleteAll(thread->PoolWaitList);
888 }
889 UnlockList(thread->PoolWaitList);
890
891 for (i = 0;i < num;i++)
892 {
893 EVENT *e = ee[i];
894
895 Set(e);
896 ReleaseEvent(e);
897 }
898
899 Free(ee);
900
901 while (true)
902 {
903 if (Count(thread->ref->c) <= 1)
904 {
905 break;
906 }
907
908 Wait(thread->release_event, 256);
909 }
910
911 ReleaseThread(thread);
912
913 #ifdef OS_WIN32
914 // For Win32: Recover the priority of the thread
915 MsRestoreThreadPriority();
916 #endif // OS_WIN32
917
918 // Register the thread itself to the thread pool
919 LockSk(thread_pool);
920 {
921 Push(thread_pool, t);
922 }
923 UnlockSk(thread_pool);
924
925 Dec(thread_count);
926 }
927 }
928
929 // Set the thread name
SetThreadName(UINT thread_id,char * name,void * param)930 void SetThreadName(UINT thread_id, char *name, void *param)
931 {
932 #ifdef OS_WIN32
933 if (IsDebug())
934 {
935 char tmp[MAX_SIZE];
936
937 if (name == NULL)
938 {
939 strcpy(tmp, "idle");
940 }
941 else
942 {
943 sprintf(tmp, "%s (0x%x)", name, (UINT)param);
944 }
945
946 Win32SetThreadName(thread_id, tmp);
947 }
948 #else // OS_WIN32
949 #ifdef _DEBUG
950 #ifdef PR_SET_NAME
951 char tmp[MAX_SIZE];
952
953 if (name == NULL)
954 {
955 strcpy(tmp, "idle");
956 }
957 else
958 {
959 sprintf(tmp, "%s (%p)", name, param);
960 }
961
962 tmp[15] = 0;
963
964 prctl(PR_SET_NAME, (unsigned long)tmp, 0, 0, 0);
965 #endif // PR_SET_NAME
966 #endif // _DEBUG
967 #endif // OS_WIN32
968 }
969
970 // Thread creation (pool)
NewThreadNamed(THREAD_PROC * thread_proc,void * param,char * name)971 THREAD *NewThreadNamed(THREAD_PROC *thread_proc, void *param, char *name)
972 {
973 THREAD *host = NULL;
974 THREAD_POOL_DATA *pd = NULL;
975 THREAD *ret;
976 // Validate arguments
977 if (thread_proc == NULL)
978 {
979 return NULL;
980 }
981
982 Inc(thread_count);
983
984 LockSk(thread_pool);
985 {
986 // Examine whether there is a thread that is currently vacant in the pool
987 host = Pop(thread_pool);
988 }
989 UnlockSk(thread_pool);
990
991 if (host == NULL)
992 {
993 // Create a new thread because a vacant thread is not found
994 pd = ZeroMalloc(sizeof(THREAD_POOL_DATA));
995 pd->Event = NewEvent();
996 pd->InitFinishEvent = NewEvent();
997 host = NewThreadInternal(ThreadPoolProc, pd);
998 WaitThreadInitInternal(host);
999 }
1000 else
1001 {
1002 pd = (THREAD_POOL_DATA *)host->param;
1003 }
1004
1005 // Creating a thread pool
1006 ret = ZeroMalloc(sizeof(THREAD));
1007 ret->ref = NewRef();
1008 ret->thread_proc = thread_proc;
1009 ret->param = param;
1010 ret->pData = NULL;
1011 ret->init_finished_event = NewEvent();
1012 ret->PoolThread = true;
1013 ret->PoolWaitList = NewList(NULL);
1014 ret->PoolHostThread = host;
1015 ret->release_event = NewEvent();
1016
1017 if (IsEmptyStr(name) == false)
1018 {
1019 ret->Name = CopyStr(name);
1020 }
1021
1022 // Run
1023 pd->ThreadProc = thread_proc;
1024 pd->Thread = ret;
1025 AddRef(ret->ref);
1026
1027 Set(pd->Event);
1028
1029 Wait(pd->InitFinishEvent, INFINITE);
1030
1031 current_num_thread++;
1032
1033 // Debug("current_num_thread = %u\n", current_num_thread);
1034
1035 return ret;
1036 }
1037
1038 // Clean up of thread (pool)
CleanupThread(THREAD * t)1039 void CleanupThread(THREAD *t)
1040 {
1041 // Validate arguments
1042 if (t == NULL)
1043 {
1044 return;
1045 }
1046
1047 ReleaseEvent(t->init_finished_event);
1048 ReleaseEvent(t->release_event);
1049 ReleaseList(t->PoolWaitList);
1050
1051 if (t->Name != NULL)
1052 {
1053 Free(t->Name);
1054 }
1055
1056 Free(t);
1057
1058 current_num_thread--;
1059 //Debug("current_num_thread = %u\n", current_num_thread);
1060 }
1061
1062 // Release thread (pool)
ReleaseThread(THREAD * t)1063 void ReleaseThread(THREAD *t)
1064 {
1065 UINT ret;
1066 EVENT *e;
1067 // Validate arguments
1068 if (t == NULL)
1069 {
1070 return;
1071 }
1072
1073 e = t->release_event;
1074 if (e != NULL)
1075 {
1076 AddRef(e->ref);
1077 }
1078
1079 ret = Release(t->ref);
1080 Set(e);
1081
1082 ReleaseEvent(e);
1083
1084 if (ret == 0)
1085 {
1086 CleanupThread(t);
1087 }
1088 }
1089
1090 // Notify the completion of the thread initialization (pool)
NoticeThreadInit(THREAD * t)1091 void NoticeThreadInit(THREAD *t)
1092 {
1093 // Validate arguments
1094 if (t == NULL)
1095 {
1096 return;
1097 }
1098
1099 // Notification
1100 Set(t->init_finished_event);
1101 }
1102
1103 // Wait the completion of the thread initialization (pool)
WaitThreadInit(THREAD * t)1104 void WaitThreadInit(THREAD *t)
1105 {
1106 // Validate arguments
1107 if (t == NULL)
1108 {
1109 return;
1110 }
1111
1112 // KS
1113 KS_INC(KS_WAITFORTHREAD_COUNT);
1114
1115 // Wait
1116 Wait(t->init_finished_event, INFINITE);
1117 }
1118
1119 // Wait for the termination of the thread (pool)
WaitThread(THREAD * t,UINT timeout)1120 bool WaitThread(THREAD *t, UINT timeout)
1121 {
1122 bool ret = false;
1123 EVENT *e = NULL;
1124 // Validate arguments
1125 if (t == NULL)
1126 {
1127 return false;
1128 }
1129
1130 LockList(t->PoolWaitList);
1131 {
1132 if (t->PoolHalting)
1133 {
1134 // Has already been stopped
1135 ret = true;
1136 }
1137 else
1138 {
1139 // Register the completion notifying event to the list
1140 e = NewEvent();
1141 AddRef(e->ref);
1142 Insert(t->PoolWaitList, e);
1143 }
1144 }
1145 UnlockList(t->PoolWaitList);
1146
1147 if (e != NULL)
1148 {
1149 // Wait Event
1150 ret = Wait(e, timeout);
1151
1152 LockList(t->PoolWaitList);
1153 {
1154 if (Delete(t->PoolWaitList, e))
1155 {
1156 ReleaseEvent(e);
1157 }
1158 }
1159 UnlockList(t->PoolWaitList);
1160
1161 ReleaseEvent(e);
1162 }
1163
1164 return ret;
1165 }
1166
1167 // Get Thread ID
ThreadId()1168 UINT ThreadId()
1169 {
1170 return OSThreadId();
1171 }
1172
1173 // Creating a thread
NewThreadInternal(THREAD_PROC * thread_proc,void * param)1174 THREAD *NewThreadInternal(THREAD_PROC *thread_proc, void *param)
1175 {
1176 THREAD *t;
1177 UINT retry = 0;
1178 // Validate arguments
1179 if (thread_proc == NULL)
1180 {
1181 return NULL;
1182 }
1183
1184 // Initialize Thread object
1185 t = ZeroMalloc(sizeof(THREAD));
1186 t->init_finished_event = NewEvent();
1187
1188 t->param = param;
1189 t->ref = NewRef();
1190 t->thread_proc = thread_proc;
1191
1192 // Wait until the OS to initialize the thread
1193 while (true)
1194 {
1195 if ((retry++) > 60)
1196 {
1197 printf("\n\n*** error: new thread create failed.\n\n");
1198 AbortExit();
1199 }
1200 if (OSInitThread(t))
1201 {
1202 break;
1203 }
1204 SleepThread(500);
1205 }
1206
1207 // KS
1208 KS_INC(KS_NEWTHREAD_COUNT);
1209
1210 return t;
1211 }
1212
1213 // Release of thread
ReleaseThreadInternal(THREAD * t)1214 void ReleaseThreadInternal(THREAD *t)
1215 {
1216 // Validate arguments
1217 if (t == NULL)
1218 {
1219 return;
1220 }
1221
1222 if (Release(t->ref) == 0)
1223 {
1224 CleanupThreadInternal(t);
1225 }
1226 }
1227
1228 // Clean up of the thread
CleanupThreadInternal(THREAD * t)1229 void CleanupThreadInternal(THREAD *t)
1230 {
1231 // Validate arguments
1232 if (t == NULL)
1233 {
1234 return;
1235 }
1236
1237 // Release of the thread
1238 OSFreeThread(t);
1239
1240 // Release the event
1241 ReleaseEvent(t->init_finished_event);
1242 // Memory release
1243 Free(t);
1244
1245 // KS
1246 KS_INC(KS_FREETHREAD_COUNT);
1247 }
1248
1249 // Wait for the termination of the thread
WaitThreadInternal(THREAD * t)1250 bool WaitThreadInternal(THREAD *t)
1251 {
1252 // Validate arguments
1253 if (t == NULL)
1254 {
1255 return false;
1256 }
1257
1258 return OSWaitThread(t);
1259 }
1260
1261 // Notify that the thread initialization is complete
NoticeThreadInitInternal(THREAD * t)1262 void NoticeThreadInitInternal(THREAD *t)
1263 {
1264 // Validate arguments
1265 if (t == NULL)
1266 {
1267 return;
1268 }
1269
1270 // Notify
1271 Set(t->init_finished_event);
1272 }
1273
1274 // Wait for completion of thread initialization
WaitThreadInitInternal(THREAD * t)1275 void WaitThreadInitInternal(THREAD *t)
1276 {
1277 // Validate arguments
1278 if (t == NULL)
1279 {
1280 return;
1281 }
1282
1283 // KS
1284 KS_INC(KS_WAITFORTHREAD_COUNT);
1285
1286 // Wait
1287 Wait(t->init_finished_event, INFINITE);
1288 }
1289
1290 // Get the date and time string by using the locale information
GetDateTimeStrEx(wchar_t * str,UINT size,SYSTEMTIME * st,LOCALE * locale)1291 void GetDateTimeStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)
1292 {
1293 wchar_t tmp1[MAX_SIZE];
1294 wchar_t tmp2[MAX_SIZE];
1295 // Validate arguments
1296 if (str == NULL || st == NULL)
1297 {
1298 return;
1299 }
1300
1301 GetDateStrEx(tmp1, sizeof(tmp1), st, locale);
1302 GetTimeStrEx(tmp2, sizeof(tmp2), st, locale);
1303 UniFormat(str, size, L"%s %s", tmp1, tmp2);
1304 }
1305
1306 // Get the time string by using the locale information
GetTimeStrEx(wchar_t * str,UINT size,SYSTEMTIME * st,LOCALE * locale)1307 void GetTimeStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)
1308 {
1309 wchar_t *tag = L"%02u%s%02u%s%02u%s";
1310 // Validate arguments
1311 if (str == NULL || st == NULL)
1312 {
1313 return;
1314 }
1315
1316 if (_GETLANG() == SE_LANG_JAPANESE || _GETLANG() == SE_LANG_CHINESE_ZH)
1317 {
1318 tag = L"%2u%s%2u%s%2u%s";
1319 }
1320
1321 locale = (locale != NULL ? locale : ¤t_locale);
1322 UniFormat(str, size,
1323 tag,
1324 st->wHour, locale->HourStr,
1325 st->wMinute, locale->MinuteStr,
1326 st->wSecond, locale->SecondStr);
1327 }
1328
1329 // Get a date string by using the locale information
GetDateStrEx(wchar_t * str,UINT size,SYSTEMTIME * st,LOCALE * locale)1330 void GetDateStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)
1331 {
1332 wchar_t *tag = L"%04u%s%02u%s%02u%s (%s)";
1333 // Validate arguments
1334 if (str == NULL || st == NULL)
1335 {
1336 return;
1337 }
1338
1339 if (_GETLANG() == SE_LANG_JAPANESE || _GETLANG() == SE_LANG_CHINESE_ZH)
1340 {
1341 tag = L"%4u%s%2u%s%2u%s(%s)";
1342 }
1343
1344 locale = (locale != NULL ? locale : ¤t_locale);
1345 UniFormat(str, size,
1346 tag,
1347 st->wYear, locale->YearStr,
1348 st->wMonth, locale->MonthStr,
1349 st->wDay, locale->DayStr,
1350 locale->DayOfWeek[st->wDayOfWeek]);
1351 }
1352
1353 // Get the time string to milliseconds (for example, 12:34:56.789)
GetTimeStrMilli(char * str,UINT size,SYSTEMTIME * st)1354 void GetTimeStrMilli(char *str, UINT size, SYSTEMTIME *st)
1355 {
1356 // Validate arguments
1357 if (st == NULL || str == NULL)
1358 {
1359 return;
1360 }
1361
1362 Format(str, size, "%02u:%02u:%02u.%03u",
1363 st->wHour, st->wMinute, st->wSecond, st->wMilliseconds);
1364 }
1365
1366 // Get the date string (example: 2004/07/23)
GetDateStr(char * str,UINT size,SYSTEMTIME * st)1367 void GetDateStr(char *str, UINT size, SYSTEMTIME *st)
1368 {
1369 // Validate arguments
1370 if (str == NULL || st == NULL)
1371 {
1372 return;
1373 }
1374
1375 Format(str, size, "%04u-%02u-%02u",
1376 st->wYear, st->wMonth, st->wDay);
1377 }
1378
1379 // Get the date and time string (example: 2004/07/23 12:34:56)
GetDateTimeStr(char * str,UINT size,SYSTEMTIME * st)1380 void GetDateTimeStr(char *str, UINT size, SYSTEMTIME *st)
1381 {
1382 // Validate arguments
1383 if (str == NULL || st == NULL)
1384 {
1385 return;
1386 }
1387
1388 Format(str, size, "%04u-%02u-%02u %02u:%02u:%02u",
1389 st->wYear, st->wMonth, st->wDay,
1390 st->wHour, st->wMinute, st->wSecond);
1391 }
1392
1393 // Get the date and time string in milliseconds (example: 2004/07/23 12:34:56.789)
GetDateTimeStrMilli(char * str,UINT size,SYSTEMTIME * st)1394 void GetDateTimeStrMilli(char *str, UINT size, SYSTEMTIME *st)
1395 {
1396 // Validate arguments
1397 if (str == NULL || st == NULL)
1398 {
1399 return;
1400 }
1401
1402 Format(str, size, "%04u-%02u-%02u %02u:%02u:%02u.%03u",
1403 st->wYear, st->wMonth, st->wDay,
1404 st->wHour, st->wMinute, st->wSecond,
1405 st->wMilliseconds);
1406 }
1407
1408
1409 // Convert string RFC3339 format (example: 2017-09-27T18:25:55.434-9:00) to UINT64
DateTimeStrRFC3339ToSystemTime64(char * str)1410 UINT64 DateTimeStrRFC3339ToSystemTime64(char *str)
1411 {
1412 SYSTEMTIME st;
1413 if (DateTimeStrRFC3339ToSystemTime(&st, str))
1414 {
1415 return SystemToUINT64(&st);
1416 }
1417 else
1418 {
1419 return 0;
1420 }
1421 }
1422
1423 // Convert string RFC3339 format (example: 2017-09-27T18:25:55.434-9:00) to SYSTEMTIME
DateTimeStrRFC3339ToSystemTime(SYSTEMTIME * st,char * str)1424 bool DateTimeStrRFC3339ToSystemTime(SYSTEMTIME *st, char *str)
1425 {
1426 bool ok = false;
1427 UINT index_plus;
1428 char tmp[MAX_PATH];
1429 Zero(st, sizeof(SYSTEMTIME));
1430 if (st == NULL || str == NULL)
1431 {
1432 return false;
1433 }
1434
1435 StrCpy(tmp, sizeof(tmp), str);
1436
1437 index_plus = SearchStrEx(tmp, "+", 0, false);
1438 if (index_plus != INFINITE)
1439 {
1440 tmp[index_plus] = 0;
1441 }
1442
1443 if (StrLen(tmp) >= 19)
1444 {
1445 if (tmp[4] == '-' && tmp[7] == '-' && tmp[10] == 'T' && tmp[13] == ':' &&
1446 tmp[16] == ':')
1447 {
1448 char str_year[16], str_month[16], str_day[16], str_hour[16], str_minute[16],
1449 str_second[16], str_msec[16];
1450
1451 StrCpy(str_year, sizeof(str_year), tmp + 0);
1452 str_year[4] = 0;
1453
1454 StrCpy(str_month, sizeof(str_month), tmp + 5);
1455 str_month[2] = 0;
1456
1457 StrCpy(str_day, sizeof(str_day), tmp + 8);
1458 str_day[2] = 0;
1459
1460 StrCpy(str_hour, sizeof(str_hour), tmp + 11);
1461 str_hour[2] = 0;
1462
1463 StrCpy(str_minute, sizeof(str_minute), tmp + 14);
1464 str_minute[2] = 0;
1465
1466 StrCpy(str_second, sizeof(str_second), tmp + 17);
1467 str_second[2] = 0;
1468
1469 str_msec[0] = 0;
1470
1471 if (StrLen(tmp) >= 21 && tmp[19] == '.')
1472 {
1473 StrCpy(str_msec, sizeof(str_msec), tmp + 20);
1474 str_msec[StrLen(tmp) - 21] = 0;
1475 while (StrLen(str_msec) < 3)
1476 {
1477 StrCat(str_msec, sizeof(str_msec), "0");
1478 }
1479 str_msec[3] = 0;
1480 }
1481
1482 st->wYear = ToInt(str_year);
1483 st->wMonth = ToInt(str_month);
1484 st->wDay = ToInt(str_day);
1485 st->wHour = ToInt(str_hour);
1486 st->wMinute = ToInt(str_minute);
1487 st->wSecond = ToInt(str_second);
1488 st->wMilliseconds = ToInt(str_msec);
1489
1490 NormalizeSystem(st);
1491
1492 ok = true;
1493 }
1494 }
1495
1496 return ok;
1497 }
1498
1499 // Get the date and time string in RFC3339 format (example: 2017-09-27T18:25:55.434-9:00)
GetDateTimeStrRFC3339(char * str,UINT size,SYSTEMTIME * st,int timezone_min)1500 void GetDateTimeStrRFC3339(char *str, UINT size, SYSTEMTIME *st, int timezone_min){
1501 // Validate arguments
1502 if (str == NULL || st == NULL)
1503 {
1504 ClearStr(str, size);
1505 return;
1506 }
1507
1508 if(timezone_min == 0){
1509 Format(str, size, "%04u-%02u-%02uT%02u:%02u:%02u.%03uZ",
1510 st->wYear, st->wMonth, st->wDay,
1511 st->wHour, st->wMinute, st->wSecond,
1512 st->wMilliseconds);
1513 }else{
1514 Format(str, size, "%04u-%02u-%02uT%02u:%02u:%02u.%03u%+02d:%02d",
1515 st->wYear, st->wMonth, st->wDay,
1516 st->wHour, st->wMinute, st->wSecond,
1517 st->wMilliseconds, timezone_min/60, timezone_min%60);
1518 }
1519 }
1520
1521 // Get the time string (in milliseconds)
GetSpanStrMilli(char * str,UINT size,UINT64 sec64)1522 void GetSpanStrMilli(char *str, UINT size, UINT64 sec64)
1523 {
1524 char tmp[MAX_SIZE];
1525 // Validate arguments
1526 if (str == NULL)
1527 {
1528 return;
1529 }
1530
1531 StrCpy(tmp, sizeof(tmp), "");
1532 if (sec64 >= (UINT64)(1000 * 3600 * 24))
1533 {
1534 Format(tmp, sizeof(tmp), "%u:", (UINT)(sec64 / (UINT64)(1000 * 3600 * 24)));
1535 }
1536
1537 Format(tmp, sizeof(tmp), "%s%02u:%02u:%02u.%03u", tmp,
1538 (UINT)(sec64 % (UINT64)(1000 * 60 * 60 * 24)) / (1000 * 60 * 60),
1539 (UINT)(sec64 % (UINT64)(1000 * 60 * 60)) / (1000 * 60),
1540 (UINT)(sec64 % (UINT64)(1000 * 60)) / 1000,
1541 (UINT)(sec64 % (UINT64)(1000)));
1542
1543 Trim(tmp);
1544 StrCpy(str, size, tmp);
1545 }
1546
1547 // Set the locale information
SetLocale(wchar_t * str)1548 void SetLocale(wchar_t *str)
1549 {
1550 wchar_t *set_locale_str;
1551 LOCALE tmp;
1552
1553 if (str != NULL)
1554 {
1555 set_locale_str = str;
1556 }
1557 else
1558 {
1559 set_locale_str = default_locale_str;
1560 }
1561
1562 if (LoadLocale(&tmp, set_locale_str) == false)
1563 {
1564 if (LoadLocale(&tmp, default_locale_str) == false)
1565 {
1566 return;
1567 }
1568 }
1569
1570 Copy(¤t_locale, &tmp, sizeof(LOCALE));
1571 }
1572
1573 #define COPY_LOCALE_STR(dest, size, src) UniStrCpy(dest, size, UniStrCmp(src, L"$") == 0 ? L"" : src)
1574
1575 // Read the locale information
LoadLocale(LOCALE * locale,wchar_t * str)1576 bool LoadLocale(LOCALE *locale, wchar_t *str)
1577 {
1578 UNI_TOKEN_LIST *tokens;
1579 UINT i;
1580 // Validate arguments
1581 if (locale == NULL || str == NULL)
1582 {
1583 return false;
1584 }
1585
1586 // Analysis of the token
1587 tokens = UniParseToken(str, L" ");
1588 if (tokens->NumTokens != 18)
1589 {
1590 UniFreeToken(tokens);
1591 return false;
1592 }
1593
1594 // Set to the structure
1595 Zero(locale, sizeof(LOCALE));
1596 COPY_LOCALE_STR(locale->YearStr, sizeof(locale->YearStr), tokens->Token[0]);
1597 COPY_LOCALE_STR(locale->MonthStr, sizeof(locale->MonthStr), tokens->Token[1]);
1598 COPY_LOCALE_STR(locale->DayStr, sizeof(locale->DayStr), tokens->Token[2]);
1599 COPY_LOCALE_STR(locale->HourStr, sizeof(locale->HourStr), tokens->Token[3]);
1600 COPY_LOCALE_STR(locale->MinuteStr, sizeof(locale->MinuteStr), tokens->Token[4]);
1601 COPY_LOCALE_STR(locale->SecondStr, sizeof(locale->SecondStr), tokens->Token[5]);
1602
1603 for (i = 0;i < 7;i++)
1604 {
1605 COPY_LOCALE_STR(locale->DayOfWeek[i], sizeof(locale->DayOfWeek[i]),
1606 tokens->Token[6 + i]);
1607 }
1608
1609 COPY_LOCALE_STR(locale->SpanDay, sizeof(locale->SpanDay), tokens->Token[13]);
1610 COPY_LOCALE_STR(locale->SpanHour, sizeof(locale->SpanHour), tokens->Token[14]);
1611 COPY_LOCALE_STR(locale->SpanMinute, sizeof(locale->SpanMinute), tokens->Token[15]);
1612 COPY_LOCALE_STR(locale->SpanSecond, sizeof(locale->SpanSecond), tokens->Token[16]);
1613
1614 COPY_LOCALE_STR(locale->Unknown, sizeof(locale->Unknown), tokens->Token[17]);
1615
1616 UniFreeToken(tokens);
1617 return true;
1618 }
1619
1620 // Convert SYSTEMTIME into DOS date
SystemToDosDate(SYSTEMTIME * st)1621 USHORT SystemToDosDate(SYSTEMTIME *st)
1622 {
1623 return (USHORT)(
1624 ((UINT)(st->wYear - 1980) << 9) |
1625 ((UINT)st->wMonth<< 5) |
1626 (UINT)st->wDay);
1627 }
System64ToDosDate(UINT64 i)1628 USHORT System64ToDosDate(UINT64 i)
1629 {
1630 SYSTEMTIME st;
1631 UINT64ToSystem(&st, i);
1632 return SystemToDosDate(&st);
1633 }
1634
1635 // Convert SYSTEMTIME into DOS time
SystemToDosTime(SYSTEMTIME * st)1636 USHORT SystemToDosTime(SYSTEMTIME *st)
1637 {
1638 return (USHORT)(
1639 ((UINT)st->wHour << 11) |
1640 ((UINT)st->wMinute << 5) |
1641 ((UINT)st->wSecond >> 1));
1642 }
System64ToDosTime(UINT64 i)1643 USHORT System64ToDosTime(UINT64 i)
1644 {
1645 SYSTEMTIME st;
1646 UINT64ToSystem(&st, i);
1647 return SystemToDosTime(&st);
1648 }
1649
1650 // Convert the tm to the SYSTEMTIME
TmToSystem(SYSTEMTIME * st,struct tm * t)1651 void TmToSystem(SYSTEMTIME *st, struct tm *t)
1652 {
1653 struct tm tmp;
1654 // Validate arguments
1655 if (st == NULL || t == NULL)
1656 {
1657 return;
1658 }
1659
1660 Copy(&tmp, t, sizeof(struct tm));
1661 NormalizeTm(&tmp);
1662
1663 Zero(st, sizeof(SYSTEMTIME));
1664 st->wYear = MAKESURE(tmp.tm_year + 1900, 1970, 2099);
1665 st->wMonth = MAKESURE(tmp.tm_mon + 1, 1, 12);
1666 st->wDay = MAKESURE(tmp.tm_mday, 1, 31);
1667 st->wDayOfWeek = MAKESURE(tmp.tm_wday, 0, 6);
1668 st->wHour = MAKESURE(tmp.tm_hour, 0, 23);
1669 st->wMinute = MAKESURE(tmp.tm_min, 0, 59);
1670 st->wSecond = MAKESURE(tmp.tm_sec, 0, 59);
1671 st->wMilliseconds = 0;
1672 }
1673
1674 // Convert the SYSTEMTIME to tm
SystemToTm(struct tm * t,SYSTEMTIME * st)1675 void SystemToTm(struct tm *t, SYSTEMTIME *st)
1676 {
1677 // Validate arguments
1678 if (t == NULL || st == NULL)
1679 {
1680 return;
1681 }
1682
1683 Zero(t, sizeof(struct tm));
1684 t->tm_year = MAKESURE(st->wYear, 1970, 2099) - 1900;
1685 t->tm_mon = MAKESURE(st->wMonth, 1, 12) - 1;
1686 t->tm_mday = MAKESURE(st->wDay, 1, 31);
1687 t->tm_hour = MAKESURE(st->wHour, 0, 23);
1688 t->tm_min = MAKESURE(st->wMinute, 0, 59);
1689 t->tm_sec = MAKESURE(st->wSecond, 0, 59);
1690
1691 t->tm_isdst = -1;
1692 NormalizeTm(t);
1693 }
1694
1695 // Convert the time_t to SYSTEMTIME
TimeToSystem(SYSTEMTIME * st,time_64t t)1696 void TimeToSystem(SYSTEMTIME *st, time_64t t)
1697 {
1698 struct tm tmp;
1699 // Validate arguments
1700 if (st == NULL)
1701 {
1702 return;
1703 }
1704
1705 TimeToTm(&tmp, t);
1706 TmToSystem(st, &tmp);
1707 }
1708
1709 // Convert the SYSTEMTIME to time_t
SystemToTime(SYSTEMTIME * st)1710 time_64t SystemToTime(SYSTEMTIME *st)
1711 {
1712 struct tm t;
1713 // Validate arguments
1714 if (st == NULL)
1715 {
1716 return 0;
1717 }
1718
1719 SystemToTm(&t, st);
1720 return TmToTime(&t);
1721 }
1722
1723 // Convert the tm to time_t
TmToTime(struct tm * t)1724 time_64t TmToTime(struct tm *t)
1725 {
1726 time_64t tmp;
1727 // Validate arguments
1728 if (t == NULL)
1729 {
1730 return 0;
1731 }
1732
1733 tmp = c_mkgmtime(t);
1734 if (tmp == (time_64t)-1)
1735 {
1736 return 0;
1737 }
1738 return tmp;
1739 }
1740
1741 // Convert time_t to tm
TimeToTm(struct tm * t,time_64t time)1742 void TimeToTm(struct tm *t, time_64t time)
1743 {
1744 // Validate arguments
1745 if (t == NULL)
1746 {
1747 return;
1748 }
1749
1750 Zero(t, sizeof(struct tm));
1751 c_gmtime_r(&time, t);
1752 }
1753
1754 // Normalize the tm
NormalizeTm(struct tm * t)1755 void NormalizeTm(struct tm *t)
1756 {
1757 time_64t tmp;
1758 // Validate arguments
1759 if (t == NULL)
1760 {
1761 return;
1762 }
1763
1764 tmp = c_mkgmtime(t);
1765 if (tmp == (time_64t)-1)
1766 {
1767 return;
1768 }
1769
1770 c_gmtime_r(&tmp, t);
1771 }
1772
1773 // Normalize the SYSTEMTIME
NormalizeSystem(SYSTEMTIME * st)1774 void NormalizeSystem(SYSTEMTIME *st)
1775 {
1776 UINT64 sec64;
1777 // Validate arguments
1778 if (st == NULL)
1779 {
1780 return;
1781 }
1782
1783 sec64 = SystemToUINT64(st);
1784 UINT64ToSystem(st, sec64);
1785 }
1786
1787 // Convert a 64-bit local time to a system time
LocalToSystem64(UINT64 t)1788 UINT64 LocalToSystem64(UINT64 t)
1789 {
1790 SYSTEMTIME st;
1791 UINT64ToSystem(&st, t);
1792 LocalToSystem(&st, &st);
1793 return SystemToUINT64(&st);
1794 }
1795
1796 // Convert the 64bit system time to local time
SystemToLocal64(UINT64 t)1797 UINT64 SystemToLocal64(UINT64 t)
1798 {
1799 SYSTEMTIME st;
1800 UINT64ToSystem(&st, t);
1801 SystemToLocal(&st, &st);
1802 return SystemToUINT64(&st);
1803 }
1804
1805 // Convert local time to system time
LocalToSystem(SYSTEMTIME * system,SYSTEMTIME * local)1806 void LocalToSystem(SYSTEMTIME *system, SYSTEMTIME *local)
1807 {
1808 UINT64 sec64;
1809 // Validate arguments
1810 if (local == NULL || system == NULL)
1811 {
1812 return;
1813 }
1814
1815 sec64 = (UINT64)((INT64)SystemToUINT64(local) - GetTimeDiffEx(local, true));
1816 UINT64ToSystem(system, sec64);
1817 }
1818
1819 // Convert the system time to local time
SystemToLocal(SYSTEMTIME * local,SYSTEMTIME * system)1820 void SystemToLocal(SYSTEMTIME *local, SYSTEMTIME *system)
1821 {
1822 UINT64 sec64;
1823 // Validate arguments
1824 if (local == NULL || system == NULL)
1825 {
1826 return;
1827 }
1828
1829 sec64 = (UINT64)((INT64)SystemToUINT64(system) + GetTimeDiffEx(system, false));
1830 UINT64ToSystem(local, sec64);
1831 }
1832
1833 // Get the time difference between the local time and the system time based on the specified time
GetTimeDiffEx(SYSTEMTIME * basetime,bool local_time)1834 INT64 GetTimeDiffEx(SYSTEMTIME *basetime, bool local_time)
1835 {
1836 time_t tmp;
1837 struct tm t1, t2;
1838 SYSTEMTIME snow;
1839 struct tm now;
1840 SYSTEMTIME s1, s2;
1841 INT64 ret;
1842
1843 Copy(&snow, basetime, sizeof(SYSTEMTIME));
1844
1845 if (sizeof(time_t) == 4)
1846 {
1847 if (snow.wYear >= 2038)
1848 {
1849 // For old systems: avoid the 2038-year problem
1850 snow.wYear = 2037;
1851 }
1852 }
1853
1854 SystemToTm(&now, &snow);
1855 if (local_time == false)
1856 {
1857 tmp = (time_t)c_mkgmtime(&now);
1858 }
1859 else
1860 {
1861 tmp = mktime(&now);
1862 }
1863
1864 if (tmp == (time_t)-1)
1865 {
1866 return 0;
1867 }
1868
1869 #ifndef OS_UNIX
1870 Copy(&t1, localtime(&tmp), sizeof(struct tm));
1871 Copy(&t2, gmtime(&tmp), sizeof(struct tm));
1872 #else // OS_UNIX
1873 localtime_r(&tmp, &t1);
1874 gmtime_r(&tmp, &t2);
1875 #endif // OS_UNIX
1876
1877 TmToSystem(&s1, &t1);
1878 TmToSystem(&s2, &t2);
1879
1880 ret = (INT)SystemToUINT64(&s1) - (INT)SystemToUINT64(&s2);
1881
1882 return ret;
1883 }
1884
1885 // Convert UINT64 to the SYSTEMTIME
UINT64ToSystem(SYSTEMTIME * st,UINT64 sec64)1886 void UINT64ToSystem(SYSTEMTIME *st, UINT64 sec64)
1887 {
1888 UINT64 tmp64;
1889 UINT sec, millisec;
1890 time_64t time;
1891 // Validate arguments
1892 if (st == NULL)
1893 {
1894 return;
1895 }
1896
1897 sec64 = SafeTime64(sec64 + 32400000ULL);
1898 tmp64 = sec64 / (UINT64)1000;
1899 millisec = (UINT)(sec64 - tmp64 * (UINT64)1000);
1900 sec = (UINT)tmp64;
1901 time = (time_64t)sec;
1902 TimeToSystem(st, time);
1903 st->wMilliseconds = (USHORT)millisec;
1904 }
1905
1906 // Convert the SYSTEMTIME to UINT64
SystemToUINT64(SYSTEMTIME * st)1907 UINT64 SystemToUINT64(SYSTEMTIME *st)
1908 {
1909 UINT64 sec64;
1910 time_64t time;
1911 // Validate arguments
1912 if (st == NULL)
1913 {
1914 return 0;
1915 }
1916
1917 time = SystemToTime(st);
1918
1919 //For times before 1970-01-01, clamp to the minimum
1920 //because we have to return an unsigned integer.
1921 //This is less wrong than casting it to UINT64
1922 //and returning a time far in the future.
1923 //For some reason we subtract 9 hours below, so
1924 //account for that here.
1925 if( time < 32400000LL ) return 0;
1926
1927 sec64 = (UINT64)time * (UINT64)1000;
1928 sec64 += st->wMilliseconds;
1929
1930 return sec64 - 32400000ULL;
1931 }
1932
1933 // Get local time in UINT64
LocalTime64()1934 UINT64 LocalTime64()
1935 {
1936 SYSTEMTIME s;
1937 LocalTime(&s);
1938 return SystemToUINT64(&s);
1939 }
1940
1941 // Get the system time in UINT64
SystemTime64()1942 UINT64 SystemTime64()
1943 {
1944 SYSTEMTIME s;
1945 SystemTime(&s);
1946 return SystemToUINT64(&s);
1947 }
1948
1949 // Get local time
LocalTime(SYSTEMTIME * st)1950 void LocalTime(SYSTEMTIME *st)
1951 {
1952 SYSTEMTIME tmp;
1953 // Validate arguments
1954 if (st == NULL)
1955 {
1956 return;
1957 }
1958
1959 SystemTime(&tmp);
1960 SystemToLocal(st, &tmp);
1961 }
1962
1963 // Get the System Time
SystemTime(SYSTEMTIME * st)1964 void SystemTime(SYSTEMTIME *st)
1965 {
1966 // Validate arguments
1967 if (st == NULL)
1968 {
1969 return;
1970 }
1971
1972 OSGetSystemTime(st);
1973
1974 // KS
1975 KS_INC(KS_GETTIME_COUNT);
1976 }
1977
c_mkgmtime(struct tm * tm)1978 time_64t c_mkgmtime(struct tm *tm)
1979 {
1980 int years, months, days, hours, minutes, seconds;
1981
1982 years = tm->tm_year + 1900; /* year - 1900 -> year */
1983 months = tm->tm_mon; /* 0..11 */
1984 days = tm->tm_mday - 1; /* 1..31 -> 0..30 */
1985 hours = tm->tm_hour; /* 0..23 */
1986 minutes = tm->tm_min; /* 0..59 */
1987 seconds = tm->tm_sec; /* 0..61 in ANSI C. */
1988
1989 ADJUST_TM(seconds, minutes, 60);
1990 ADJUST_TM(minutes, hours, 60);
1991 ADJUST_TM(hours, days, 24);
1992 ADJUST_TM(months, years, 12);
1993 if (days < 0)
1994 do {
1995 if (--months < 0) {
1996 --years;
1997 months = 11;
1998 }
1999 days += monthlen(months, years);
2000 } while (days < 0);
2001 else
2002 while (days >= monthlen(months, years)) {
2003 days -= monthlen(months, years);
2004 if (++months >= 12) {
2005 ++years;
2006 months = 0;
2007 }
2008 }
2009
2010 /* Restore adjusted values in tm structure */
2011 tm->tm_year = years - 1900;
2012 tm->tm_mon = months;
2013 tm->tm_mday = days + 1;
2014 tm->tm_hour = hours;
2015 tm->tm_min = minutes;
2016 tm->tm_sec = seconds;
2017
2018 /* Set `days' to the number of days into the year. */
2019 days += ydays[months] + (months > 1 && leap (years));
2020 tm->tm_yday = days;
2021
2022 /* Now calculate `days' to the number of days since Jan 1, 1970. */
2023 days = (unsigned)days + 365 * (unsigned)(years - 1970) +
2024 (unsigned)(nleap (years));
2025 tm->tm_wday = ((unsigned)days + 4) % 7; /* Jan 1, 1970 was Thursday. */
2026 tm->tm_isdst = 0;
2027
2028 if (years < 1970)
2029 return (time_64t)-1;
2030
2031 #if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX))
2032 #if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX))
2033 if (years > TM_YEAR_MAX ||
2034 (years == TM_YEAR_MAX &&
2035 (tm->tm_yday > ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +
2036 (TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) ||
2037 (tm->tm_yday == ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +
2038 (TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) &&
2039 (hours > TM_HOUR_MAX ||
2040 (hours == TM_HOUR_MAX &&
2041 (minutes > TM_MIN_MAX ||
2042 (minutes == TM_MIN_MAX && seconds > TM_SEC_MAX) )))))))
2043 return (time_64t)-1;
2044 #endif
2045 #endif
2046
2047 return (time_64t)(86400L * (unsigned long)(unsigned)days +
2048 3600L * (unsigned long)hours +
2049 (unsigned long)(60 * minutes + seconds));
2050 }
2051
2052 // Get the system timer
Tick()2053 UINT Tick()
2054 {
2055 // KS
2056 KS_INC(KS_GETTICK_COUNT);
2057 return OSGetTick();
2058 }
2059
2060 // Sleep thread
SleepThread(UINT time)2061 void SleepThread(UINT time)
2062 {
2063 // KS
2064 KS_INC(KS_SLEEPTHREAD_COUNT);
2065
2066 OSSleep(time);
2067 }
2068
2069 // Yield
YieldCpu()2070 void YieldCpu()
2071 {
2072 OSYield();
2073 }
2074
2075 // Stop system (abnormal termination)
AbortExit()2076 void AbortExit()
2077 {
2078 #ifdef OS_WIN32
2079 _exit(1);
2080 #else // OS_WIN32
2081
2082 #ifdef RLIMIT_CORE
2083 UnixSetResourceLimit(RLIMIT_CORE, 0);
2084 #endif // RLIMIT_CORE
2085
2086 abort();
2087 #endif // OS_WIN32
2088 }
2089
2090
AbortExitEx(char * msg)2091 void AbortExitEx(char *msg)
2092 {
2093 FILE *f;
2094 // Validate arguments
2095 if (msg == NULL)
2096 {
2097 msg = "Unknown Error";
2098 }
2099
2100 f = fopen("abort_error_log.txt", "w");
2101 if (f != NULL)
2102 {
2103 fwrite(msg, 1, strlen(msg), f);
2104 fclose(f);
2105 }
2106
2107 fputs("Fatal Error: ", stdout);
2108 fputs(msg, stdout);
2109 fputs("\r\n", stdout);
2110
2111 #ifdef OS_WIN32
2112 _exit(1);
2113 #else // OS_WIN32
2114
2115 #ifdef RLIMIT_CORE
2116 UnixSetResourceLimit(RLIMIT_CORE, 0);
2117 #endif // RLIMIT_CORE
2118
2119 abort();
2120 #endif // OS_WIN32
2121 }
2122
2123