1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2025-06-29 04:15:08 +03:00
SoftEtherVPN/src/Mayaqua/Kernel.c
Daiyuu Nobori 2dec52b875 Heap area protection of memory has been enhanced.
When memory is released and reallocated, a random security value called a canary is written to the before/after area of memory, and if the value has been modified, the process is terminated (restarted) for safety, assuming it is a buffer overflow of the memory area. This feature may effectively prevent confidentiality or integrity violations in the event that some heap area overflow vulnerability is discovered in this system in the future.
2023-10-07 04:42:34 +02:00

2147 lines
41 KiB
C

// SoftEther VPN Source Code - Developer Edition Master Branch
// Mayaqua Kernel
// Kernel.c
// System service processing routine
#include "Kernel.h"
#include "Encrypt.h"
#include "Internat.h"
#include "Mayaqua.h"
#include "Memory.h"
#include "Microsoft.h"
#include "Object.h"
#include "Str.h"
#include "Table.h"
#include "Tracking.h"
#include "Unix.h"
#include "Win32.h"
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef OS_UNIX
#include <sys/time.h>
#endif
#ifndef TM_YEAR_MAX
#define TM_YEAR_MAX 2106
#endif
#ifndef TM_MON_MAX
#define TM_MON_MAX 1
#endif
#ifndef TM_MDAY_MAX
#define TM_MDAY_MAX 7
#endif
#ifndef TM_HOUR_MAX
#define TM_HOUR_MAX 6
#endif
#ifndef TM_MIN_MAX
#define TM_MIN_MAX 28
#endif
#ifndef TM_SEC_MAX
#define TM_SEC_MAX 14
#endif
#define ADJUST_TM(tm_member, tm_carry, modulus) \
if ((tm_member) < 0){ \
tm_carry -= (1 - ((tm_member)+1) / (modulus)); \
tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \
} else if ((tm_member) >= (modulus)) { \
tm_carry += (tm_member) / (modulus); \
tm_member = (tm_member) % (modulus); \
}
#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
#define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
#define leapday(m, y) ((m) == 1 && leap (y))
#define monthlen(m, y) (ydays[(m)+1] - ydays[m] + leapday (m, y))
static int ydays[] =
{
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
};
static UINT current_num_thread = 0;
static UINT cached_number_of_cpus = 0;
static wchar_t *default_locale_str =
L"- - $ : : $ Sun Mon Tue Wed Thu Fri Sat : : : $ (None)";
static LOCALE current_locale;
LOCK *tick_manual_lock = NULL;
#define MONSPERYEAR 12
#define DAYSPERNYEAR 365
#define DAYSPERLYEAR 366
#define SECSPERMIN 60
#define SECSPERHOUR (60*60)
#define SECSPERDAY (24*60*60)
#define DAYSPERWEEK 7
#define TM_SUNDAY 0
#define TM_MONDAY 1
#define TM_TUESDAY 2
#define TM_WEDNESDAY 3
#define TM_THURSDAY 4
#define TM_FRIDAY 5
#define TM_SATURDAY 6
#define TM_YEAR_BASE 1900
#define EPOCH_YEAR 1970
#define EPOCH_WDAY TM_THURSDAY
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
static const int mon_lengths[2][MONSPERYEAR] = {
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
static const int year_lengths[2] = {
DAYSPERNYEAR, DAYSPERLYEAR
};
/*
* Taken from FreeBSD src / lib / libc / stdtime / localtime.c 1.43 revision.
* localtime.c 7.78.
* tzfile.h 1.8
* adapted to be replacement gmtime_r.
*/
static void
c_timesub(timep, offset, tmp)
const time_64t * const timep;
const long offset;
struct tm * const tmp;
{
INT64 days;
INT64 rem;
INT64 y;
int yleap;
const int * ip;
days = *timep / SECSPERDAY;
rem = *timep % SECSPERDAY;
rem += (offset);
while (rem < 0) {
rem += SECSPERDAY;
--days;
}
while (rem >= SECSPERDAY) {
rem -= SECSPERDAY;
++days;
}
tmp->tm_hour = (int) (rem / SECSPERHOUR);
rem = rem % SECSPERHOUR;
tmp->tm_min = (int) (rem / SECSPERMIN);
/*
** A positive leap second requires a special
** representation. This uses "... ??:59:60" et seq.
*/
tmp->tm_sec = (int) (rem % SECSPERMIN) ;
tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
if (tmp->tm_wday < 0)
tmp->tm_wday += DAYSPERWEEK;
y = EPOCH_YEAR;
#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
INT64 newy;
newy = y + days / DAYSPERNYEAR;
if (days < 0)
--newy;
days -= (newy - y) * DAYSPERNYEAR +
LEAPS_THRU_END_OF(newy - 1) -
LEAPS_THRU_END_OF(y - 1);
y = newy;
}
tmp->tm_year = (int)(y - TM_YEAR_BASE);
tmp->tm_yday = (int) days;
ip = mon_lengths[yleap];
for (tmp->tm_mon = 0; days >= (INT64) ip[tmp->tm_mon]; ++(tmp->tm_mon))
days = days - (INT64) ip[tmp->tm_mon];
tmp->tm_mday = (int) (days + 1);
tmp->tm_isdst = 0;
}
/*
* Re-entrant version of gmtime.
*/
struct tm * c_gmtime_r(const time_64t* timep, struct tm *tm)
{
c_timesub(timep, 0L, tm);
return tm;
}
// Get the real-time system timer
UINT TickRealtime()
{
#if defined(OS_WIN32) || defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) || defined(CLOCK_HIGHRES) || defined(UNIX_MACOS)
return Tick() + 1;
#else
return TickRealtimeManual() + 1;
#endif
}
#ifndef OS_WIN32
static UINT64 last_manual_tick = 0;
static UINT64 manual_tick_add_value = 0;
// For systems which not have clock_gettime (such as MacOS X)
UINT TickRealtimeManual()
{
UINT64 ret;
Lock(tick_manual_lock);
{
ret = TickGetRealtimeTickValue64();
if (last_manual_tick != 0 && (last_manual_tick > ret))
{
manual_tick_add_value += (last_manual_tick - ret);
}
last_manual_tick = ret;
}
Unlock(tick_manual_lock);
return (UINT)(ret + manual_tick_add_value);
}
// Returns a appropriate value from the current time
UINT64 TickGetRealtimeTickValue64()
{
struct timeval tv;
struct timezone tz;
UINT64 ret;
memset(&tv, 0, sizeof(tv));
memset(&tz, 0, sizeof(tz));
gettimeofday(&tv, &tz);
if (sizeof(tv.tv_sec) != 4)
{
ret = (UINT64)tv.tv_sec * 1000ULL + (UINT64)tv.tv_usec / 1000ULL;
}
else
{
ret = (UINT64)((UINT64)((UINT)tv.tv_sec)) * 1000ULL + (UINT64)tv.tv_usec / 1000ULL;
}
return ret;
}
#endif // OS_WIN32
// Get the number of CPUs
UINT GetNumberOfCpu()
{
UINT ret = 0;
if (cached_number_of_cpus == 0)
{
UINT i = 0;
#ifdef OS_WIN32
i = Win32GetNumberOfCpuInner();
#else // OS_WIN32
i = UnixGetNumberOfCpuInner();
#endif // OS_WIN32
if (i == 0)
{
i = 8;
}
cached_number_of_cpus = i;
}
ret = cached_number_of_cpus;
if (ret == 0)
{
ret = 1;
}
if (ret > 128)
{
ret = 128;
}
return ret;
}
// Creating a thread list
LIST *NewThreadList()
{
LIST *o = NewList(NULL);
return o;
}
// Add the thread to the thread list
void AddThreadToThreadList(LIST *o, THREAD *t)
{
// Validate arguments
if (o == NULL || t == NULL)
{
return;
}
LockList(o);
{
if (IsInList(o, t) == false)
{
AddRef(t->ref);
Add(o, t);
}
}
UnlockList(o);
}
// Maintain thread list
void MaintainThreadList(LIST *o)
{
UINT i;
LIST *delete_list = NULL;
// Validate arguments
if (o == NULL)
{
return;
}
LockList(o);
{
for (i = 0;i < LIST_NUM(o);i++)
{
THREAD *t = LIST_DATA(o, i);
if (t->Stopped)
{
if (delete_list == NULL)
{
delete_list = NewListFast(NULL);
}
Add(delete_list, t);
}
}
if (delete_list != NULL)
{
for (i = 0;i < LIST_NUM(delete_list);i++)
{
THREAD *t = LIST_DATA(delete_list, i);
ReleaseThread(t);
Delete(o, t);
}
ReleaseList(delete_list);
}
}
UnlockList(o);
}
// Stop all the threads in the thread list
void StopThreadList(LIST *o)
{
UINT i;
// Validate arguments
if (o == NULL)
{
return;
}
LockList(o);
{
for (i = 0;i < LIST_NUM(o);i++)
{
THREAD *t = LIST_DATA(o, i);
WaitThread(t, INFINITE);
}
}
UnlockList(o);
}
// Release the thread list
void FreeThreadList(LIST *o)
{
UINT i;
// Validate arguments
if (o == NULL)
{
return;
}
LockList(o);
{
for (i = 0;i < LIST_NUM(o);i++)
{
THREAD *t = LIST_DATA(o, i);
WaitThread(t, INFINITE);
ReleaseThread(t);
}
DeleteAll(o);
}
UnlockList(o);
ReleaseList(o);
}
// Get the home directory
void GetHomeDirW(wchar_t *path, UINT size)
{
// Validate arguments
if (path == NULL)
{
return;
}
if (GetEnvW(L"HOME", path, size) == false)
{
wchar_t drive[MAX_SIZE];
wchar_t hpath[MAX_SIZE];
if (GetEnvW(L"HOMEDRIVE", drive, sizeof(drive)) &&
GetEnvW(L"HOMEPATH", hpath, sizeof(hpath)))
{
UniFormat(path, size, L"%s%s", drive, hpath);
}
else
{
#ifdef OS_WIN32
Win32GetCurrentDirW(path, size);
#else // OS_WIN32
UnixGetCurrentDirW(path, size);
#endif // OS_WIN32
}
}
}
// Get the environment variable string
bool GetEnv(char *name, char *data, UINT size)
{
char *ret;
// Validate arguments
if (name == NULL || data == NULL)
{
return false;
}
StrCpy(data, size, "");
ret = getenv(name);
if (ret == NULL)
{
return false;
}
StrCpy(data, size, ret);
return true;
}
bool GetEnvW(wchar_t *name, wchar_t *data, UINT size)
{
#ifdef OS_WIN32
return GetEnvW_ForWin32(name, data, size);
#else // OS_WIN32
return GetEnvW_ForUnix(name, data, size);
#endif // OS_WIN32
}
#ifdef OS_WIN32
bool GetEnvW_ForWin32(wchar_t *name, wchar_t *data, UINT size)
{
wchar_t *ret;
// Validate arguments
if (name == NULL || data == NULL)
{
return false;
}
if (IsNt() == false)
{
bool ret;
char *name_a = CopyUniToStr(name);
char data_a[MAX_SIZE];
ret = GetEnv(name_a, data_a, sizeof(data_a));
if (ret)
{
StrToUni(data, size, data_a);
}
Free(name_a);
return ret;
}
UniStrCpy(data, size, L"");
ret = _wgetenv(name);
if (ret == NULL)
{
return false;
}
UniStrCpy(data, size, ret);
return true;
}
#endif // OS_WIN32
#ifdef OS_UNIX
bool GetEnvW_ForUnix(wchar_t *name, wchar_t *data, UINT size)
{
char *name_a;
bool ret;
char data_a[MAX_SIZE];
// Validate arguments
if (name == NULL || data == NULL)
{
return false;
}
name_a = CopyUniToUtf(name);
ret = GetEnv(name_a, data_a, sizeof(data_a));
if (ret)
{
UtfToUni(data, size, data_a);
}
Free(name_a);
return ret;
}
#endif // OS_UNIX
// Get the memory information
void GetMemInfo(MEMINFO *info)
{
OSGetMemInfo(info);
}
// Start the single-instance
INSTANCE *NewSingleInstance(char *instance_name)
{
return NewSingleInstanceEx(instance_name, false);
}
INSTANCE *NewSingleInstanceEx(char *instance_name, bool user_local)
{
char name[MAX_SIZE];
INSTANCE *ret;
void *data;
if (instance_name != NULL)
{
if (user_local == false)
{
HashInstanceName(name, sizeof(name), instance_name);
}
else
{
HashInstanceNameLocal(name, sizeof(name), instance_name);
}
data = OSNewSingleInstance(name);
}
else
{
data = OSNewSingleInstance(NULL);
}
if (data == NULL)
{
return NULL;
}
ret = ZeroMalloc(sizeof(INSTANCE));
if (instance_name != NULL)
{
ret->Name = CopyStr(instance_name);
}
ret->pData = data;
return ret;
}
// Release of single instance
void FreeSingleInstance(INSTANCE *inst)
{
// Validate arguments
if (inst == NULL)
{
return;
}
OSFreeSingleInstance(inst->pData);
if (inst->Name != NULL)
{
Free(inst->Name);
}
Free(inst);
}
// Hashing the instance name
void HashInstanceName(char *name, UINT size, char *instance_name)
{
char tmp[MAX_SIZE];
UCHAR hash[SHA1_SIZE];
char key[11];
// Validate arguments
if (name == NULL || instance_name == NULL)
{
return;
}
StrCpy(tmp, sizeof(tmp), instance_name);
Trim(tmp);
StrUpper(tmp);
Sha0(hash, tmp, StrLen(tmp));
BinToStr(key, sizeof(key), hash, 5);
key[10] = 0;
Format(name, size, "VPN-%s", key);
StrCpy(tmp, sizeof(tmp), name);
Format(name, size, "Global\\%s", tmp);
}
void HashInstanceNameLocal(char *name, UINT size, char *instance_name)
{
char tmp[MAX_SIZE];
UCHAR hash[SHA1_SIZE];
char key[11];
// Validate arguments
if (name == NULL || instance_name == NULL)
{
return;
}
StrCpy(tmp, sizeof(tmp), instance_name);
Trim(tmp);
StrUpper(tmp);
Sha0(hash, tmp, StrLen(tmp));
BinToStr(key, sizeof(key), hash, 5);
key[10] = 0;
Format(name, size, "VPN-%s", key);
StrCpy(tmp, sizeof(tmp), name);
Format(name, size, "Local\\%s", tmp);
}
// Run the process
bool Run(char *filename, char *arg, bool hide, bool wait)
{
// Validate arguments
if (filename == NULL)
{
return false;
}
return OSRun(filename, arg, hide, wait);
}
bool RunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait)
{
// Validate arguments
if (filename == NULL)
{
return false;
}
return OSRunW(filename, arg, hide, wait);
}
// Date and time related functions
void GetDateTimeStr64Uni(wchar_t *str, UINT size, UINT64 sec64)
{
char tmp[MAX_SIZE];
if (str == NULL)
{
return;
}
GetDateTimeStr64(tmp, sizeof(tmp), sec64);
StrToUni(str, size, tmp);
}
void GetDateTimeStr64(char *str, UINT size, UINT64 sec64)
{
SYSTEMTIME st;
UINT64ToSystem(&st, sec64);
GetDateTimeStr(str, size, &st);
}
void GetDateTimeStrMilli64(char *str, UINT size, UINT64 sec64)
{
SYSTEMTIME st;
UINT64ToSystem(&st, sec64);
GetDateTimeStrMilli(str, size, &st);
}
void GetDateTimeStrMilli64ForFileName(char *str, UINT size, UINT64 sec64)
{
SYSTEMTIME st;
UINT64ToSystem(&st, sec64);
GetDateTimeStrMilliForFileName(str, size, &st);
}
void GetDateTimeStrMilliForFileName(char *str, UINT size, SYSTEMTIME *tm)
{
Format(str, size, "%04u%02u%02u_%02u%02u%02u",
tm->wYear, tm->wMonth, tm->wDay, tm->wHour, tm->wMinute, tm->wSecond);
}
void GetDateStr64(char *str, UINT size, UINT64 sec64)
{
SYSTEMTIME st;
if (sec64 == 0)
{
StrCpy(str, size, "(Unknown)");
return;
}
UINT64ToSystem(&st, sec64);
GetDateStr(str, size, &st);
}
void GetDateTimeStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)
{
SYSTEMTIME st;
if (locale == NULL)
{
locale = &current_locale;
}
if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
{
UniStrCpy(str, size, locale->Unknown);
return;
}
UINT64ToSystem(&st, sec64);
GetDateTimeStrEx(str, size, &st, locale);
}
void GetDateStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)
{
SYSTEMTIME st;
if (locale == NULL)
{
locale = &current_locale;
}
if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
{
UniStrCpy(str, size, locale->Unknown);
return;
}
UINT64ToSystem(&st, sec64);
GetDateStrEx(str, size, &st, locale);
}
void GetTimeStrMilli64(char *str, UINT size, UINT64 sec64)
{
SYSTEMTIME st;
if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
{
StrCpy(str, size, "(Unknown)");
return;
}
UINT64ToSystem(&st, sec64);
GetTimeStrMilli(str, size, &st);
}
// Convert to a time to be used safely in the current POSIX implementation
UINT64 SafeTime64(UINT64 sec64)
{
return MAKESURE(sec64, 0, 4102243323123ULL);
}
// Thread pool
static SK *thread_pool = NULL;
static COUNTER *thread_count = NULL;
// Initialization of thread pool
void InitThreading()
{
thread_pool = NewSk();
thread_count = NewCounter();
}
// Release of thread pool
void FreeThreading()
{
while (true)
{
if (Count(thread_count) == 0)
{
break;
}
SleepThread(25);
}
while (true)
{
THREAD_POOL_DATA *pd;
THREAD *t = Pop(thread_pool);
if (t == NULL)
{
break;
}
pd = (THREAD_POOL_DATA *)t->param;
pd->ThreadProc = NULL;
Set(pd->Event);
WaitThreadInternal(t);
pd = (THREAD_POOL_DATA *)t->param;
ReleaseEvent(pd->Event);
ReleaseEvent(pd->InitFinishEvent);
ReleaseThreadInternal(t);
Free(pd);
}
ReleaseSk(thread_pool);
DeleteCounter(thread_count);
thread_count = NULL;
}
// Thread pool procedure
void ThreadPoolProc(THREAD *t, void *param)
{
THREAD_POOL_DATA *pd;
// Validate arguments
if (t == NULL)
{
return;
}
pd = (THREAD_POOL_DATA *)param;
NoticeThreadInitInternal(t);
while (true)
{
THREAD *thread;
UINT i, num;
EVENT **ee;
// Wait for the next job
Wait(pd->Event, INFINITE);
if (pd->ThreadProc == NULL)
{
// Stop the pool thread
break;
}
thread = pd->Thread;
thread->ThreadId = ThreadId();
// Initialization is completed
Set(pd->InitFinishEvent);
// Set the thread name
if (thread->Name != NULL)
{
SetThreadName(thread->ThreadId, thread->Name, thread->param);
}
else
{
SetThreadName(thread->ThreadId, "Unknown", 0);
}
// Run the thread procedure
pd->ThreadProc(pd->Thread, thread->param);
// Set the thread name
SetThreadName(thread->ThreadId, NULL, 0);
pd->Thread->Stopped = true;
thread->PoolHalting = true;
// Set the waiting event list
LockList(thread->PoolWaitList);
{
num = LIST_NUM(thread->PoolWaitList);
ee = ToArray(thread->PoolWaitList);
DeleteAll(thread->PoolWaitList);
}
UnlockList(thread->PoolWaitList);
for (i = 0;i < num;i++)
{
EVENT *e = ee[i];
Set(e);
ReleaseEvent(e);
}
Free(ee);
while (true)
{
if (Count(thread->ref->c) <= 1)
{
break;
}
Wait(thread->release_event, 256);
}
ReleaseThread(thread);
#ifdef OS_WIN32
// For Win32: Recover the priority of the thread
MsRestoreThreadPriority();
#endif // OS_WIN32
// Register the thread itself to the thread pool
LockSk(thread_pool);
{
Push(thread_pool, t);
}
UnlockSk(thread_pool);
Dec(thread_count);
}
}
// Set the thread name
void SetThreadName(UINT thread_id, char *name, void *param)
{
#ifdef OS_WIN32
if (IsDebug())
{
char tmp[MAX_SIZE];
if (name == NULL)
{
strcpy(tmp, "idle");
}
else
{
sprintf(tmp, "%s (0x%x)", name, (UINT)param);
}
Win32SetThreadName(thread_id, tmp);
}
#else // OS_WIN32
#ifdef _DEBUG
#ifdef PR_SET_NAME
char tmp[MAX_SIZE];
if (name == NULL)
{
strcpy(tmp, "idle");
}
else
{
sprintf(tmp, "%s (%p)", name, param);
}
tmp[15] = 0;
prctl(PR_SET_NAME, (unsigned long)tmp, 0, 0, 0);
#endif // PR_SET_NAME
#endif // _DEBUG
#endif // OS_WIN32
}
// Thread creation (pool)
THREAD *NewThreadNamed(THREAD_PROC *thread_proc, void *param, char *name)
{
THREAD *host = NULL;
THREAD_POOL_DATA *pd = NULL;
THREAD *ret;
// Validate arguments
if (thread_proc == NULL)
{
return NULL;
}
Inc(thread_count);
LockSk(thread_pool);
{
// Examine whether there is a thread that is currently vacant in the pool
host = Pop(thread_pool);
}
UnlockSk(thread_pool);
if (host == NULL)
{
// Create a new thread because a vacant thread is not found
pd = ZeroMalloc(sizeof(THREAD_POOL_DATA));
pd->Event = NewEvent();
pd->InitFinishEvent = NewEvent();
host = NewThreadInternal(ThreadPoolProc, pd);
WaitThreadInitInternal(host);
}
else
{
pd = (THREAD_POOL_DATA *)host->param;
}
// Creating a thread pool
ret = ZeroMalloc(sizeof(THREAD));
ret->ref = NewRef();
ret->thread_proc = thread_proc;
ret->param = param;
ret->pData = NULL;
ret->init_finished_event = NewEvent();
ret->PoolThread = true;
ret->PoolWaitList = NewList(NULL);
ret->PoolHostThread = host;
ret->release_event = NewEvent();
if (IsEmptyStr(name) == false)
{
ret->Name = CopyStr(name);
}
// Run
pd->ThreadProc = thread_proc;
pd->Thread = ret;
AddRef(ret->ref);
Set(pd->Event);
Wait(pd->InitFinishEvent, INFINITE);
current_num_thread++;
// Debug("current_num_thread = %u\n", current_num_thread);
return ret;
}
// Clean up of thread (pool)
void CleanupThread(THREAD *t)
{
// Validate arguments
if (t == NULL)
{
return;
}
ReleaseEvent(t->init_finished_event);
ReleaseEvent(t->release_event);
ReleaseList(t->PoolWaitList);
if (t->Name != NULL)
{
Free(t->Name);
}
Free(t);
current_num_thread--;
//Debug("current_num_thread = %u\n", current_num_thread);
}
// Release thread (pool)
void ReleaseThread(THREAD *t)
{
UINT ret;
EVENT *e;
// Validate arguments
if (t == NULL)
{
return;
}
e = t->release_event;
if (e != NULL)
{
AddRef(e->ref);
}
ret = Release(t->ref);
Set(e);
ReleaseEvent(e);
if (ret == 0)
{
CleanupThread(t);
}
}
// Notify the completion of the thread initialization (pool)
void NoticeThreadInit(THREAD *t)
{
// Validate arguments
if (t == NULL)
{
return;
}
// Notification
Set(t->init_finished_event);
}
// Wait the completion of the thread initialization (pool)
void WaitThreadInit(THREAD *t)
{
// Validate arguments
if (t == NULL)
{
return;
}
// KS
KS_INC(KS_WAITFORTHREAD_COUNT);
// Wait
Wait(t->init_finished_event, INFINITE);
}
// Wait for the termination of the thread (pool)
bool WaitThread(THREAD *t, UINT timeout)
{
bool ret = false;
EVENT *e = NULL;
// Validate arguments
if (t == NULL)
{
return false;
}
LockList(t->PoolWaitList);
{
if (t->PoolHalting)
{
// Has already been stopped
ret = true;
}
else
{
// Register the completion notifying event to the list
e = NewEvent();
AddRef(e->ref);
Insert(t->PoolWaitList, e);
}
}
UnlockList(t->PoolWaitList);
if (e != NULL)
{
// Wait Event
ret = Wait(e, timeout);
LockList(t->PoolWaitList);
{
if (Delete(t->PoolWaitList, e))
{
ReleaseEvent(e);
}
}
UnlockList(t->PoolWaitList);
ReleaseEvent(e);
}
return ret;
}
// Get Thread ID
UINT ThreadId()
{
return OSThreadId();
}
// Creating a thread
THREAD *NewThreadInternal(THREAD_PROC *thread_proc, void *param)
{
THREAD *t;
UINT retry = 0;
// Validate arguments
if (thread_proc == NULL)
{
return NULL;
}
// Initialize Thread object
t = ZeroMalloc(sizeof(THREAD));
t->init_finished_event = NewEvent();
t->param = param;
t->ref = NewRef();
t->thread_proc = thread_proc;
// Wait until the OS to initialize the thread
while (true)
{
if ((retry++) > 60)
{
printf("\n\n*** error: new thread create failed.\n\n");
AbortExit();
}
if (OSInitThread(t))
{
break;
}
SleepThread(500);
}
// KS
KS_INC(KS_NEWTHREAD_COUNT);
return t;
}
// Release of thread
void ReleaseThreadInternal(THREAD *t)
{
// Validate arguments
if (t == NULL)
{
return;
}
if (Release(t->ref) == 0)
{
CleanupThreadInternal(t);
}
}
// Clean up of the thread
void CleanupThreadInternal(THREAD *t)
{
// Validate arguments
if (t == NULL)
{
return;
}
// Release of the thread
OSFreeThread(t);
// Release the event
ReleaseEvent(t->init_finished_event);
// Memory release
Free(t);
// KS
KS_INC(KS_FREETHREAD_COUNT);
}
// Wait for the termination of the thread
bool WaitThreadInternal(THREAD *t)
{
// Validate arguments
if (t == NULL)
{
return false;
}
return OSWaitThread(t);
}
// Notify that the thread initialization is complete
void NoticeThreadInitInternal(THREAD *t)
{
// Validate arguments
if (t == NULL)
{
return;
}
// Notify
Set(t->init_finished_event);
}
// Wait for completion of thread initialization
void WaitThreadInitInternal(THREAD *t)
{
// Validate arguments
if (t == NULL)
{
return;
}
// KS
KS_INC(KS_WAITFORTHREAD_COUNT);
// Wait
Wait(t->init_finished_event, INFINITE);
}
// Get the date and time string by using the locale information
void GetDateTimeStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)
{
wchar_t tmp1[MAX_SIZE];
wchar_t tmp2[MAX_SIZE];
// Validate arguments
if (str == NULL || st == NULL)
{
return;
}
GetDateStrEx(tmp1, sizeof(tmp1), st, locale);
GetTimeStrEx(tmp2, sizeof(tmp2), st, locale);
UniFormat(str, size, L"%s %s", tmp1, tmp2);
}
// Get the time string by using the locale information
void GetTimeStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)
{
wchar_t *tag = L"%02u%s%02u%s%02u%s";
// Validate arguments
if (str == NULL || st == NULL)
{
return;
}
if (_GETLANG() == SE_LANG_JAPANESE || _GETLANG() == SE_LANG_CHINESE_ZH)
{
tag = L"%2u%s%2u%s%2u%s";
}
locale = (locale != NULL ? locale : &current_locale);
UniFormat(str, size,
tag,
st->wHour, locale->HourStr,
st->wMinute, locale->MinuteStr,
st->wSecond, locale->SecondStr);
}
// Get a date string by using the locale information
void GetDateStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)
{
wchar_t *tag = L"%04u%s%02u%s%02u%s (%s)";
// Validate arguments
if (str == NULL || st == NULL)
{
return;
}
if (_GETLANG() == SE_LANG_JAPANESE || _GETLANG() == SE_LANG_CHINESE_ZH)
{
tag = L"%4u%s%2u%s%2u%s(%s)";
}
locale = (locale != NULL ? locale : &current_locale);
UniFormat(str, size,
tag,
st->wYear, locale->YearStr,
st->wMonth, locale->MonthStr,
st->wDay, locale->DayStr,
locale->DayOfWeek[st->wDayOfWeek]);
}
// Get the time string to milliseconds (for example, 12:34:56.789)
void GetTimeStrMilli(char *str, UINT size, SYSTEMTIME *st)
{
// Validate arguments
if (st == NULL || str == NULL)
{
return;
}
Format(str, size, "%02u:%02u:%02u.%03u",
st->wHour, st->wMinute, st->wSecond, st->wMilliseconds);
}
// Get the date string (example: 2004/07/23)
void GetDateStr(char *str, UINT size, SYSTEMTIME *st)
{
// Validate arguments
if (str == NULL || st == NULL)
{
return;
}
Format(str, size, "%04u-%02u-%02u",
st->wYear, st->wMonth, st->wDay);
}
// Get the date and time string (example: 2004/07/23 12:34:56)
void GetDateTimeStr(char *str, UINT size, SYSTEMTIME *st)
{
// Validate arguments
if (str == NULL || st == NULL)
{
return;
}
Format(str, size, "%04u-%02u-%02u %02u:%02u:%02u",
st->wYear, st->wMonth, st->wDay,
st->wHour, st->wMinute, st->wSecond);
}
// Get the date and time string in milliseconds (example: 2004/07/23 12:34:56.789)
void GetDateTimeStrMilli(char *str, UINT size, SYSTEMTIME *st)
{
// Validate arguments
if (str == NULL || st == NULL)
{
return;
}
Format(str, size, "%04u-%02u-%02u %02u:%02u:%02u.%03u",
st->wYear, st->wMonth, st->wDay,
st->wHour, st->wMinute, st->wSecond,
st->wMilliseconds);
}
// Convert string RFC3339 format (example: 2017-09-27T18:25:55.434-9:00) to UINT64
UINT64 DateTimeStrRFC3339ToSystemTime64(char *str)
{
SYSTEMTIME st;
if (DateTimeStrRFC3339ToSystemTime(&st, str))
{
return SystemToUINT64(&st);
}
else
{
return 0;
}
}
// Convert string RFC3339 format (example: 2017-09-27T18:25:55.434-9:00) to SYSTEMTIME
bool DateTimeStrRFC3339ToSystemTime(SYSTEMTIME *st, char *str)
{
bool ok = false;
UINT index_plus;
char tmp[MAX_PATH];
Zero(st, sizeof(SYSTEMTIME));
if (st == NULL || str == NULL)
{
return false;
}
StrCpy(tmp, sizeof(tmp), str);
index_plus = SearchStrEx(tmp, "+", 0, false);
if (index_plus != INFINITE)
{
tmp[index_plus] = 0;
}
if (StrLen(tmp) >= 19)
{
if (tmp[4] == '-' && tmp[7] == '-' && tmp[10] == 'T' && tmp[13] == ':' &&
tmp[16] == ':')
{
char str_year[16], str_month[16], str_day[16], str_hour[16], str_minute[16],
str_second[16], str_msec[16];
StrCpy(str_year, sizeof(str_year), tmp + 0);
str_year[4] = 0;
StrCpy(str_month, sizeof(str_month), tmp + 5);
str_month[2] = 0;
StrCpy(str_day, sizeof(str_day), tmp + 8);
str_day[2] = 0;
StrCpy(str_hour, sizeof(str_hour), tmp + 11);
str_hour[2] = 0;
StrCpy(str_minute, sizeof(str_minute), tmp + 14);
str_minute[2] = 0;
StrCpy(str_second, sizeof(str_second), tmp + 17);
str_second[2] = 0;
str_msec[0] = 0;
if (StrLen(tmp) >= 21 && tmp[19] == '.')
{
StrCpy(str_msec, sizeof(str_msec), tmp + 20);
str_msec[StrLen(tmp) - 21] = 0;
while (StrLen(str_msec) < 3)
{
StrCat(str_msec, sizeof(str_msec), "0");
}
str_msec[3] = 0;
}
st->wYear = ToInt(str_year);
st->wMonth = ToInt(str_month);
st->wDay = ToInt(str_day);
st->wHour = ToInt(str_hour);
st->wMinute = ToInt(str_minute);
st->wSecond = ToInt(str_second);
st->wMilliseconds = ToInt(str_msec);
NormalizeSystem(st);
ok = true;
}
}
return ok;
}
// Get the date and time string in RFC3339 format (example: 2017-09-27T18:25:55.434-9:00)
void GetDateTimeStrRFC3339(char *str, UINT size, SYSTEMTIME *st, int timezone_min){
// Validate arguments
if (str == NULL || st == NULL)
{
ClearStr(str, size);
return;
}
if(timezone_min == 0){
Format(str, size, "%04u-%02u-%02uT%02u:%02u:%02u.%03uZ",
st->wYear, st->wMonth, st->wDay,
st->wHour, st->wMinute, st->wSecond,
st->wMilliseconds);
}else{
Format(str, size, "%04u-%02u-%02uT%02u:%02u:%02u.%03u%+02d:%02d",
st->wYear, st->wMonth, st->wDay,
st->wHour, st->wMinute, st->wSecond,
st->wMilliseconds, timezone_min/60, timezone_min%60);
}
}
// Get the time string (in milliseconds)
void GetSpanStrMilli(char *str, UINT size, UINT64 sec64)
{
char tmp[MAX_SIZE];
// Validate arguments
if (str == NULL)
{
return;
}
StrCpy(tmp, sizeof(tmp), "");
if (sec64 >= (UINT64)(1000 * 3600 * 24))
{
Format(tmp, sizeof(tmp), "%u:", (UINT)(sec64 / (UINT64)(1000 * 3600 * 24)));
}
Format(tmp, sizeof(tmp), "%s%02u:%02u:%02u.%03u", tmp,
(UINT)(sec64 % (UINT64)(1000 * 60 * 60 * 24)) / (1000 * 60 * 60),
(UINT)(sec64 % (UINT64)(1000 * 60 * 60)) / (1000 * 60),
(UINT)(sec64 % (UINT64)(1000 * 60)) / 1000,
(UINT)(sec64 % (UINT64)(1000)));
Trim(tmp);
StrCpy(str, size, tmp);
}
// Set the locale information
void SetLocale(wchar_t *str)
{
wchar_t *set_locale_str;
LOCALE tmp;
if (str != NULL)
{
set_locale_str = str;
}
else
{
set_locale_str = default_locale_str;
}
if (LoadLocale(&tmp, set_locale_str) == false)
{
if (LoadLocale(&tmp, default_locale_str) == false)
{
return;
}
}
Copy(&current_locale, &tmp, sizeof(LOCALE));
}
#define COPY_LOCALE_STR(dest, size, src) UniStrCpy(dest, size, UniStrCmp(src, L"$") == 0 ? L"" : src)
// Read the locale information
bool LoadLocale(LOCALE *locale, wchar_t *str)
{
UNI_TOKEN_LIST *tokens;
UINT i;
// Validate arguments
if (locale == NULL || str == NULL)
{
return false;
}
// Analysis of the token
tokens = UniParseToken(str, L" ");
if (tokens->NumTokens != 18)
{
UniFreeToken(tokens);
return false;
}
// Set to the structure
Zero(locale, sizeof(LOCALE));
COPY_LOCALE_STR(locale->YearStr, sizeof(locale->YearStr), tokens->Token[0]);
COPY_LOCALE_STR(locale->MonthStr, sizeof(locale->MonthStr), tokens->Token[1]);
COPY_LOCALE_STR(locale->DayStr, sizeof(locale->DayStr), tokens->Token[2]);
COPY_LOCALE_STR(locale->HourStr, sizeof(locale->HourStr), tokens->Token[3]);
COPY_LOCALE_STR(locale->MinuteStr, sizeof(locale->MinuteStr), tokens->Token[4]);
COPY_LOCALE_STR(locale->SecondStr, sizeof(locale->SecondStr), tokens->Token[5]);
for (i = 0;i < 7;i++)
{
COPY_LOCALE_STR(locale->DayOfWeek[i], sizeof(locale->DayOfWeek[i]),
tokens->Token[6 + i]);
}
COPY_LOCALE_STR(locale->SpanDay, sizeof(locale->SpanDay), tokens->Token[13]);
COPY_LOCALE_STR(locale->SpanHour, sizeof(locale->SpanHour), tokens->Token[14]);
COPY_LOCALE_STR(locale->SpanMinute, sizeof(locale->SpanMinute), tokens->Token[15]);
COPY_LOCALE_STR(locale->SpanSecond, sizeof(locale->SpanSecond), tokens->Token[16]);
COPY_LOCALE_STR(locale->Unknown, sizeof(locale->Unknown), tokens->Token[17]);
UniFreeToken(tokens);
return true;
}
// Convert SYSTEMTIME into DOS date
USHORT SystemToDosDate(SYSTEMTIME *st)
{
return (USHORT)(
((UINT)(st->wYear - 1980) << 9) |
((UINT)st->wMonth<< 5) |
(UINT)st->wDay);
}
USHORT System64ToDosDate(UINT64 i)
{
SYSTEMTIME st;
UINT64ToSystem(&st, i);
return SystemToDosDate(&st);
}
// Convert SYSTEMTIME into DOS time
USHORT SystemToDosTime(SYSTEMTIME *st)
{
return (USHORT)(
((UINT)st->wHour << 11) |
((UINT)st->wMinute << 5) |
((UINT)st->wSecond >> 1));
}
USHORT System64ToDosTime(UINT64 i)
{
SYSTEMTIME st;
UINT64ToSystem(&st, i);
return SystemToDosTime(&st);
}
// Convert the tm to the SYSTEMTIME
void TmToSystem(SYSTEMTIME *st, struct tm *t)
{
struct tm tmp;
// Validate arguments
if (st == NULL || t == NULL)
{
return;
}
Copy(&tmp, t, sizeof(struct tm));
NormalizeTm(&tmp);
Zero(st, sizeof(SYSTEMTIME));
st->wYear = MAKESURE(tmp.tm_year + 1900, 1970, 2099);
st->wMonth = MAKESURE(tmp.tm_mon + 1, 1, 12);
st->wDay = MAKESURE(tmp.tm_mday, 1, 31);
st->wDayOfWeek = MAKESURE(tmp.tm_wday, 0, 6);
st->wHour = MAKESURE(tmp.tm_hour, 0, 23);
st->wMinute = MAKESURE(tmp.tm_min, 0, 59);
st->wSecond = MAKESURE(tmp.tm_sec, 0, 59);
st->wMilliseconds = 0;
}
// Convert the SYSTEMTIME to tm
void SystemToTm(struct tm *t, SYSTEMTIME *st)
{
// Validate arguments
if (t == NULL || st == NULL)
{
return;
}
Zero(t, sizeof(struct tm));
t->tm_year = MAKESURE(st->wYear, 1970, 2099) - 1900;
t->tm_mon = MAKESURE(st->wMonth, 1, 12) - 1;
t->tm_mday = MAKESURE(st->wDay, 1, 31);
t->tm_hour = MAKESURE(st->wHour, 0, 23);
t->tm_min = MAKESURE(st->wMinute, 0, 59);
t->tm_sec = MAKESURE(st->wSecond, 0, 59);
t->tm_isdst = -1;
NormalizeTm(t);
}
// Convert the time_t to SYSTEMTIME
void TimeToSystem(SYSTEMTIME *st, time_64t t)
{
struct tm tmp;
// Validate arguments
if (st == NULL)
{
return;
}
TimeToTm(&tmp, t);
TmToSystem(st, &tmp);
}
// Convert the SYSTEMTIME to time_t
time_64t SystemToTime(SYSTEMTIME *st)
{
struct tm t;
// Validate arguments
if (st == NULL)
{
return 0;
}
SystemToTm(&t, st);
return TmToTime(&t);
}
// Convert the tm to time_t
time_64t TmToTime(struct tm *t)
{
time_64t tmp;
// Validate arguments
if (t == NULL)
{
return 0;
}
tmp = c_mkgmtime(t);
if (tmp == (time_64t)-1)
{
return 0;
}
return tmp;
}
// Convert time_t to tm
void TimeToTm(struct tm *t, time_64t time)
{
// Validate arguments
if (t == NULL)
{
return;
}
Zero(t, sizeof(struct tm));
c_gmtime_r(&time, t);
}
// Normalize the tm
void NormalizeTm(struct tm *t)
{
time_64t tmp;
// Validate arguments
if (t == NULL)
{
return;
}
tmp = c_mkgmtime(t);
if (tmp == (time_64t)-1)
{
return;
}
c_gmtime_r(&tmp, t);
}
// Normalize the SYSTEMTIME
void NormalizeSystem(SYSTEMTIME *st)
{
UINT64 sec64;
// Validate arguments
if (st == NULL)
{
return;
}
sec64 = SystemToUINT64(st);
UINT64ToSystem(st, sec64);
}
// Convert a 64-bit local time to a system time
UINT64 LocalToSystem64(UINT64 t)
{
SYSTEMTIME st;
UINT64ToSystem(&st, t);
LocalToSystem(&st, &st);
return SystemToUINT64(&st);
}
// Convert the 64bit system time to local time
UINT64 SystemToLocal64(UINT64 t)
{
SYSTEMTIME st;
UINT64ToSystem(&st, t);
SystemToLocal(&st, &st);
return SystemToUINT64(&st);
}
// Convert local time to system time
void LocalToSystem(SYSTEMTIME *system, SYSTEMTIME *local)
{
UINT64 sec64;
// Validate arguments
if (local == NULL || system == NULL)
{
return;
}
sec64 = (UINT64)((INT64)SystemToUINT64(local) - GetTimeDiffEx(local, true));
UINT64ToSystem(system, sec64);
}
// Convert the system time to local time
void SystemToLocal(SYSTEMTIME *local, SYSTEMTIME *system)
{
UINT64 sec64;
// Validate arguments
if (local == NULL || system == NULL)
{
return;
}
sec64 = (UINT64)((INT64)SystemToUINT64(system) + GetTimeDiffEx(system, false));
UINT64ToSystem(local, sec64);
}
// Get the time difference between the local time and the system time based on the specified time
INT64 GetTimeDiffEx(SYSTEMTIME *basetime, bool local_time)
{
time_t tmp;
struct tm t1, t2;
SYSTEMTIME snow;
struct tm now;
SYSTEMTIME s1, s2;
INT64 ret;
Copy(&snow, basetime, sizeof(SYSTEMTIME));
if (sizeof(time_t) == 4)
{
if (snow.wYear >= 2038)
{
// For old systems: avoid the 2038-year problem
snow.wYear = 2037;
}
}
SystemToTm(&now, &snow);
if (local_time == false)
{
tmp = (time_t)c_mkgmtime(&now);
}
else
{
tmp = mktime(&now);
}
if (tmp == (time_t)-1)
{
return 0;
}
#ifndef OS_UNIX
Copy(&t1, localtime(&tmp), sizeof(struct tm));
Copy(&t2, gmtime(&tmp), sizeof(struct tm));
#else // OS_UNIX
localtime_r(&tmp, &t1);
gmtime_r(&tmp, &t2);
#endif // OS_UNIX
TmToSystem(&s1, &t1);
TmToSystem(&s2, &t2);
ret = (INT)SystemToUINT64(&s1) - (INT)SystemToUINT64(&s2);
return ret;
}
// Convert UINT64 to the SYSTEMTIME
void UINT64ToSystem(SYSTEMTIME *st, UINT64 sec64)
{
UINT64 tmp64;
UINT sec, millisec;
time_64t time;
// Validate arguments
if (st == NULL)
{
return;
}
sec64 = SafeTime64(sec64 + 32400000ULL);
tmp64 = sec64 / (UINT64)1000;
millisec = (UINT)(sec64 - tmp64 * (UINT64)1000);
sec = (UINT)tmp64;
time = (time_64t)sec;
TimeToSystem(st, time);
st->wMilliseconds = (USHORT)millisec;
}
// Convert the SYSTEMTIME to UINT64
UINT64 SystemToUINT64(SYSTEMTIME *st)
{
UINT64 sec64;
time_64t time;
// Validate arguments
if (st == NULL)
{
return 0;
}
time = SystemToTime(st);
//For times before 1970-01-01, clamp to the minimum
//because we have to return an unsigned integer.
//This is less wrong than casting it to UINT64
//and returning a time far in the future.
//For some reason we subtract 9 hours below, so
//account for that here.
if( time < 32400000LL ) return 0;
sec64 = (UINT64)time * (UINT64)1000;
sec64 += st->wMilliseconds;
return sec64 - 32400000ULL;
}
// Get local time in UINT64
UINT64 LocalTime64()
{
SYSTEMTIME s;
LocalTime(&s);
return SystemToUINT64(&s);
}
// Get the system time in UINT64
UINT64 SystemTime64()
{
SYSTEMTIME s;
SystemTime(&s);
return SystemToUINT64(&s);
}
// Get local time
void LocalTime(SYSTEMTIME *st)
{
SYSTEMTIME tmp;
// Validate arguments
if (st == NULL)
{
return;
}
SystemTime(&tmp);
SystemToLocal(st, &tmp);
}
// Get the System Time
void SystemTime(SYSTEMTIME *st)
{
// Validate arguments
if (st == NULL)
{
return;
}
OSGetSystemTime(st);
// KS
KS_INC(KS_GETTIME_COUNT);
}
time_64t c_mkgmtime(struct tm *tm)
{
int years, months, days, hours, minutes, seconds;
years = tm->tm_year + 1900; /* year - 1900 -> year */
months = tm->tm_mon; /* 0..11 */
days = tm->tm_mday - 1; /* 1..31 -> 0..30 */
hours = tm->tm_hour; /* 0..23 */
minutes = tm->tm_min; /* 0..59 */
seconds = tm->tm_sec; /* 0..61 in ANSI C. */
ADJUST_TM(seconds, minutes, 60);
ADJUST_TM(minutes, hours, 60);
ADJUST_TM(hours, days, 24);
ADJUST_TM(months, years, 12);
if (days < 0)
do {
if (--months < 0) {
--years;
months = 11;
}
days += monthlen(months, years);
} while (days < 0);
else
while (days >= monthlen(months, years)) {
days -= monthlen(months, years);
if (++months >= 12) {
++years;
months = 0;
}
}
/* Restore adjusted values in tm structure */
tm->tm_year = years - 1900;
tm->tm_mon = months;
tm->tm_mday = days + 1;
tm->tm_hour = hours;
tm->tm_min = minutes;
tm->tm_sec = seconds;
/* Set `days' to the number of days into the year. */
days += ydays[months] + (months > 1 && leap (years));
tm->tm_yday = days;
/* Now calculate `days' to the number of days since Jan 1, 1970. */
days = (unsigned)days + 365 * (unsigned)(years - 1970) +
(unsigned)(nleap (years));
tm->tm_wday = ((unsigned)days + 4) % 7; /* Jan 1, 1970 was Thursday. */
tm->tm_isdst = 0;
if (years < 1970)
return (time_64t)-1;
#if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX))
#if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX))
if (years > TM_YEAR_MAX ||
(years == TM_YEAR_MAX &&
(tm->tm_yday > ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +
(TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) ||
(tm->tm_yday == ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +
(TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) &&
(hours > TM_HOUR_MAX ||
(hours == TM_HOUR_MAX &&
(minutes > TM_MIN_MAX ||
(minutes == TM_MIN_MAX && seconds > TM_SEC_MAX) )))))))
return (time_64t)-1;
#endif
#endif
return (time_64t)(86400L * (unsigned long)(unsigned)days +
3600L * (unsigned long)hours +
(unsigned long)(60 * minutes + seconds));
}
// Get the system timer
UINT Tick()
{
// KS
KS_INC(KS_GETTICK_COUNT);
return OSGetTick();
}
// Sleep thread
void SleepThread(UINT time)
{
// KS
KS_INC(KS_SLEEPTHREAD_COUNT);
OSSleep(time);
}
// Yield
void YieldCpu()
{
OSYield();
}
// Stop system (abnormal termination)
void AbortExit()
{
#ifdef OS_WIN32
_exit(1);
#else // OS_WIN32
#ifdef RLIMIT_CORE
UnixSetResourceLimit(RLIMIT_CORE, 0);
#endif // RLIMIT_CORE
abort();
#endif // OS_WIN32
}
void AbortExitEx(char *msg)
{
FILE *f;
// Validate arguments
if (msg == NULL)
{
msg = "Unknown Error";
}
f = fopen("abort_error_log.txt", "w");
if (f != NULL)
{
SYSTEMTIME time = { 0 };
char time_str[128] = { 0 };
char *crlf = "\r\n";
char *tag = "---------";
LocalTime(&time);
sprintf(time_str, "%04u-%02u-%02u %02u:%02u:%02u",
time.wYear, time.wMonth, time.wDay,
time.wHour, time.wMinute, time.wSecond);
fwrite(tag, 1, strlen(tag), f);
fwrite(crlf, 1, strlen(crlf), f);
fwrite(time_str, 1, strlen(time_str), f);
fwrite(crlf, 1, strlen(crlf), f);
fwrite(msg, 1, strlen(msg), f);
fwrite(crlf, 1, strlen(crlf), f);
fwrite(crlf, 1, strlen(crlf), f);
fclose(f);
}
fputs("Fatal Error: ", stdout);
fputs(msg, stdout);
fputs("\r\n", stdout);
#ifdef OS_WIN32
_exit(1);
#else // OS_WIN32
#ifdef RLIMIT_CORE
UnixSetResourceLimit(RLIMIT_CORE, 0);
#endif // RLIMIT_CORE
abort();
#endif // OS_WIN32
}