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 = &current_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 = &current_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 : &current_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 : &current_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(&current_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