2017-06-30 19:08:11 +00:00
|
|
|
/*
|
|
|
|
* Mr. 4th Dimention - Allen Webster
|
|
|
|
*
|
2017-06-30 22:09:18 +00:00
|
|
|
* 30.06.2017
|
2017-06-30 19:08:11 +00:00
|
|
|
*
|
|
|
|
* General unix functions
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
// TOP
|
|
|
|
|
2017-11-14 21:35:17 +00:00
|
|
|
#if !defined(FD_CHECK)
|
|
|
|
#define FD_CHECK()
|
|
|
|
#endif
|
|
|
|
|
2017-06-30 21:28:09 +00:00
|
|
|
struct Unix_Vars{
|
2017-07-03 15:43:51 +00:00
|
|
|
b32 did_first_log;
|
2017-06-30 21:28:09 +00:00
|
|
|
};
|
2017-07-18 22:09:16 +00:00
|
|
|
global Unix_Vars unixvars;
|
2017-06-30 21:28:09 +00:00
|
|
|
|
2017-06-30 22:57:20 +00:00
|
|
|
//
|
|
|
|
// 4ed Path
|
|
|
|
//
|
|
|
|
|
2017-07-19 16:33:12 +00:00
|
|
|
internal
|
|
|
|
Sys_Get_Current_Path_Sig(system_get_current_path){
|
|
|
|
i32 result = 0;
|
|
|
|
char *d = getcwd(out, capacity);
|
|
|
|
if (d == out){
|
|
|
|
result = strlen(out);
|
|
|
|
}
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
2017-06-30 21:28:09 +00:00
|
|
|
//
|
|
|
|
// Logging
|
|
|
|
//
|
|
|
|
|
|
|
|
internal
|
|
|
|
Sys_Log_Sig(system_log){
|
2017-07-18 22:09:16 +00:00
|
|
|
if (plat_settings.use_log == LogTo_LogFile){
|
2017-07-03 15:43:51 +00:00
|
|
|
char file_path_space[1024];
|
|
|
|
String file_path = make_fixed_width_string(file_path_space);
|
|
|
|
file_path.size = system_get_4ed_path(file_path.str, file_path.memory_size);
|
|
|
|
append_sc(&file_path, "4coder_log.txt");
|
|
|
|
terminate_with_null(&file_path);
|
|
|
|
|
|
|
|
i32 fd = -1;
|
|
|
|
if (unixvars.did_first_log){
|
|
|
|
fd = open(file_path.str, O_WRONLY | O_CREAT | O_APPEND, 00640);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
fd = open(file_path.str, O_WRONLY | O_CREAT | O_TRUNC, 00640);
|
|
|
|
unixvars.did_first_log = true;
|
|
|
|
}
|
|
|
|
|
2017-06-30 21:28:09 +00:00
|
|
|
if (fd >= 0){
|
|
|
|
do{
|
|
|
|
ssize_t written = write(fd, message, length);
|
|
|
|
if (written != -1){
|
|
|
|
length -= written;
|
|
|
|
message += written;
|
|
|
|
}
|
|
|
|
} while(length > 0);
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
}
|
2017-07-18 22:09:16 +00:00
|
|
|
else if (plat_settings.use_log == LogTo_Stdout){
|
2017-07-03 15:43:51 +00:00
|
|
|
fwrite(message, 1, length, stdout);
|
|
|
|
}
|
2017-06-30 21:28:09 +00:00
|
|
|
}
|
|
|
|
|
2017-06-30 22:09:18 +00:00
|
|
|
//
|
|
|
|
// Shared system functions (system_shared.h)
|
|
|
|
//
|
|
|
|
|
|
|
|
internal
|
|
|
|
Sys_File_Can_Be_Made_Sig(system_file_can_be_made){
|
|
|
|
b32 result = access((char*)filename, W_OK) == 0;
|
2017-07-03 15:43:51 +00:00
|
|
|
LOGF("%s = %d\n", filename, result);
|
2017-06-30 22:09:18 +00:00
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
2017-06-30 21:28:09 +00:00
|
|
|
//
|
|
|
|
// Memory
|
|
|
|
//
|
|
|
|
|
2017-07-18 23:17:40 +00:00
|
|
|
internal void*
|
|
|
|
system_memory_allocate_extended(void *base, umem size){
|
2017-06-30 21:28:09 +00:00
|
|
|
// NOTE(allen): This must return the exact base of the vpage.
|
|
|
|
// We will count on the user to keep track of size themselves.
|
2017-07-18 23:17:40 +00:00
|
|
|
void *result = mmap(base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
|
|
if (result == MAP_FAILED){
|
2017-07-03 15:43:51 +00:00
|
|
|
LOG("error: mmap failed\n");
|
2017-07-18 23:17:40 +00:00
|
|
|
result = 0;
|
2017-06-30 21:28:09 +00:00
|
|
|
}
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
2017-07-18 23:17:40 +00:00
|
|
|
internal
|
|
|
|
Sys_Memory_Allocate_Sig(system_memory_allocate){
|
|
|
|
void *result = system_memory_allocate_extended(0, size);
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
2017-06-30 21:28:09 +00:00
|
|
|
internal
|
|
|
|
Sys_Memory_Set_Protection_Sig(system_memory_set_protection){
|
|
|
|
bool32 result = true;
|
|
|
|
|
|
|
|
int protect = 0;
|
|
|
|
switch (flags & 0x7){
|
|
|
|
case 0: protect = PROT_NONE; break;
|
|
|
|
|
|
|
|
case MemProtect_Read:
|
|
|
|
protect = PROT_READ; break;
|
|
|
|
|
|
|
|
case MemProtect_Write:
|
|
|
|
case MemProtect_Read|MemProtect_Write:
|
|
|
|
protect = PROT_READ | PROT_WRITE; break;
|
|
|
|
|
|
|
|
case MemProtect_Execute:
|
|
|
|
protect = PROT_EXEC; break;
|
|
|
|
|
|
|
|
case MemProtect_Execute|MemProtect_Read:
|
|
|
|
protect = PROT_READ | PROT_EXEC; break;
|
|
|
|
|
|
|
|
// NOTE(inso): some W^X protection things might be unhappy about this one
|
|
|
|
case MemProtect_Execute|MemProtect_Write:
|
|
|
|
case MemProtect_Execute|MemProtect_Write|MemProtect_Read:
|
|
|
|
protect = PROT_READ | PROT_WRITE | PROT_EXEC; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(mprotect(ptr, size, protect) == -1){
|
|
|
|
result = 0;
|
2017-07-03 15:43:51 +00:00
|
|
|
LOG("error: mprotect\n");
|
2017-06-30 21:28:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
Sys_Memory_Free_Sig(system_memory_free){
|
|
|
|
// NOTE(allen): This must take the exact base of the vpage.
|
|
|
|
munmap(ptr, size);
|
|
|
|
}
|
2017-06-30 19:08:11 +00:00
|
|
|
|
2017-06-30 22:29:34 +00:00
|
|
|
//
|
|
|
|
// Files
|
|
|
|
//
|
|
|
|
|
|
|
|
internal
|
|
|
|
Sys_Set_File_List_Sig(system_set_file_list){
|
2017-07-01 01:32:35 +00:00
|
|
|
if (directory == 0){
|
2017-06-30 22:29:34 +00:00
|
|
|
system_memory_free(file_list->block, file_list->block_size);
|
|
|
|
file_list->block = 0;
|
|
|
|
file_list->block_size = 0;
|
|
|
|
file_list->infos = 0;
|
|
|
|
file_list->count = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-14 00:22:12 +00:00
|
|
|
LOGF("%s\n", directory);
|
2017-06-30 22:29:34 +00:00
|
|
|
|
2017-07-01 01:32:35 +00:00
|
|
|
DIR *d = opendir(directory);
|
|
|
|
if (d != 0){
|
2017-06-30 22:29:34 +00:00
|
|
|
if (canon_directory_out != 0){
|
|
|
|
u32 length = copy_fast_unsafe_cc(canon_directory_out, directory);
|
|
|
|
if (canon_directory_out[length-1] != '/'){
|
|
|
|
canon_directory_out[length++] = '/';
|
|
|
|
}
|
|
|
|
canon_directory_out[length] = 0;
|
|
|
|
*canon_directory_size_out = length;
|
|
|
|
}
|
|
|
|
|
2017-07-01 01:32:35 +00:00
|
|
|
i32 character_count = 0;
|
|
|
|
i32 file_count = 0;
|
|
|
|
for (struct dirent *entry = readdir(d);
|
2017-06-30 22:29:34 +00:00
|
|
|
entry != 0;
|
|
|
|
entry = readdir(d)){
|
2017-07-01 01:32:35 +00:00
|
|
|
char *fname = entry->d_name;
|
2017-06-30 22:29:34 +00:00
|
|
|
if (match_cc(fname, ".") || match_cc(fname, "..")){
|
|
|
|
continue;
|
|
|
|
}
|
2017-07-01 01:32:35 +00:00
|
|
|
++file_count;
|
|
|
|
i32 size = 0;
|
|
|
|
for (; fname[size]; ++size);
|
2017-06-30 22:29:34 +00:00
|
|
|
character_count += size + 1;
|
|
|
|
}
|
|
|
|
|
2017-07-01 01:32:35 +00:00
|
|
|
i32 required_size = character_count + file_count * sizeof(File_Info);
|
2017-06-30 22:29:34 +00:00
|
|
|
if (file_list->block_size < required_size){
|
|
|
|
system_memory_free(file_list->block, file_list->block_size);
|
|
|
|
file_list->block = system_memory_allocate(required_size);
|
|
|
|
file_list->block_size = required_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
file_list->infos = (File_Info*)file_list->block;
|
2017-07-01 01:32:35 +00:00
|
|
|
char *cursor = (char*)(file_list->infos + file_count);
|
2017-06-30 22:29:34 +00:00
|
|
|
|
|
|
|
if (file_list->block != 0){
|
|
|
|
rewinddir(d);
|
2017-07-01 01:32:35 +00:00
|
|
|
File_Info *info_ptr = file_list->infos;
|
|
|
|
for (struct dirent *entry = readdir(d);
|
2017-06-30 22:29:34 +00:00
|
|
|
entry != 0;
|
|
|
|
entry = readdir(d)){
|
2017-07-01 01:32:35 +00:00
|
|
|
char *fname = entry->d_name;
|
2017-06-30 22:29:34 +00:00
|
|
|
if (match_cc(fname, ".") || match_cc(fname, "..")){
|
|
|
|
continue;
|
|
|
|
}
|
2017-07-01 01:32:35 +00:00
|
|
|
char *cursor_start = cursor;
|
|
|
|
i32 length = copy_fast_unsafe_cc(cursor_start, fname);
|
2017-06-30 22:29:34 +00:00
|
|
|
cursor += length;
|
|
|
|
|
|
|
|
if(entry->d_type == DT_LNK){
|
|
|
|
struct stat st;
|
|
|
|
if(stat(entry->d_name, &st) != -1){
|
|
|
|
info_ptr->folder = S_ISDIR(st.st_mode);
|
2017-07-01 01:32:35 +00:00
|
|
|
}
|
|
|
|
else{
|
2017-06-30 22:29:34 +00:00
|
|
|
info_ptr->folder = 0;
|
|
|
|
}
|
2017-07-01 01:32:35 +00:00
|
|
|
}
|
|
|
|
else{
|
2017-06-30 22:29:34 +00:00
|
|
|
info_ptr->folder = (entry->d_type == DT_DIR);
|
|
|
|
}
|
|
|
|
|
|
|
|
info_ptr->filename = cursor_start;
|
|
|
|
info_ptr->filename_len = length;
|
|
|
|
*cursor++ = 0;
|
|
|
|
++info_ptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
file_list->count = file_count;
|
|
|
|
|
|
|
|
closedir(d);
|
2017-07-01 01:32:35 +00:00
|
|
|
}
|
|
|
|
else{
|
2017-06-30 22:29:34 +00:00
|
|
|
system_memory_free(file_list->block, file_list->block_size);
|
|
|
|
file_list->block = 0;
|
|
|
|
file_list->block_size = 0;
|
|
|
|
file_list->infos = 0;
|
|
|
|
file_list->count = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
Sys_Get_Canonical_Sig(system_get_canonical){
|
2017-07-01 02:19:51 +00:00
|
|
|
char* path = (char*) alloca(len + 1);
|
2017-06-30 22:29:34 +00:00
|
|
|
char* write_p = path;
|
|
|
|
const char* read_p = filename;
|
|
|
|
|
|
|
|
// return 0 for relative paths (e.g. cmdline args)
|
2017-07-01 02:19:51 +00:00
|
|
|
if(len > 0 && filename[0] != '/'){
|
2017-06-30 22:29:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (max == 0){
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
max -= 1;
|
|
|
|
|
2017-11-14 00:22:12 +00:00
|
|
|
while (read_p < filename + len){
|
|
|
|
if (read_p == filename || read_p[0] == '/'){
|
|
|
|
if (read_p[1] == '/'){
|
2017-06-30 22:29:34 +00:00
|
|
|
++read_p;
|
2017-11-14 00:22:12 +00:00
|
|
|
}
|
|
|
|
else if(read_p[1] == '.'){
|
|
|
|
if (read_p[2] == '/' || !read_p[2]){
|
2017-06-30 22:29:34 +00:00
|
|
|
read_p += 2;
|
2017-07-01 02:19:51 +00:00
|
|
|
} else if(read_p[2] == '.' && (read_p[3] == '/' || !read_p[3])){
|
2017-06-30 22:29:34 +00:00
|
|
|
while(write_p > path && *--write_p != '/');
|
|
|
|
read_p += 3;
|
2017-11-14 00:22:12 +00:00
|
|
|
}
|
|
|
|
else {
|
2017-06-30 22:29:34 +00:00
|
|
|
*write_p++ = *read_p++;
|
|
|
|
}
|
2017-11-14 00:22:12 +00:00
|
|
|
}
|
|
|
|
else{
|
2017-06-30 22:29:34 +00:00
|
|
|
*write_p++ = *read_p++;
|
|
|
|
}
|
2017-11-14 00:22:12 +00:00
|
|
|
}
|
|
|
|
else{
|
2017-06-30 22:29:34 +00:00
|
|
|
*write_p++ = *read_p++;
|
|
|
|
}
|
|
|
|
}
|
2017-11-14 00:22:12 +00:00
|
|
|
if (write_p == path) *write_p++ = '/';
|
2017-06-30 22:29:34 +00:00
|
|
|
|
2017-11-14 00:22:12 +00:00
|
|
|
if (max >= (write_p - path)){
|
2017-06-30 22:29:34 +00:00
|
|
|
memcpy(buffer, path, write_p - path);
|
2017-11-14 00:22:12 +00:00
|
|
|
}
|
|
|
|
else{
|
2017-06-30 22:29:34 +00:00
|
|
|
write_p = path;
|
|
|
|
}
|
|
|
|
|
2017-07-18 20:51:44 +00:00
|
|
|
#if defined(FRED_INTERNAL)
|
2017-11-14 00:22:12 +00:00
|
|
|
if (len != (write_p - path) || memcmp(filename, path, len) != 0){
|
2017-07-03 15:43:51 +00:00
|
|
|
LOGF("[%.*s] -> [%.*s]\n", len, filename, (int)(write_p - path), path);
|
2017-06-30 22:29:34 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
u32 length = (i32)(write_p - path);
|
|
|
|
buffer[length] = 0;
|
|
|
|
return(length);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
Sys_Load_Handle_Sig(system_load_handle){
|
2017-07-03 15:43:51 +00:00
|
|
|
b32 result = false;
|
2017-06-30 22:29:34 +00:00
|
|
|
|
2017-11-14 21:35:17 +00:00
|
|
|
FD_CHECK();
|
|
|
|
|
2017-07-03 15:43:51 +00:00
|
|
|
i32 fd = open(filename, O_RDONLY);
|
2017-11-14 00:22:12 +00:00
|
|
|
if (fd == -1 || fd == 0){
|
|
|
|
LOGF("upable to open file descriptor for %s\n", filename);
|
2017-07-18 20:51:44 +00:00
|
|
|
}
|
|
|
|
else{
|
2017-11-14 00:22:12 +00:00
|
|
|
LOGF("file descriptor (%d) == file %s\n", fd, filename);
|
|
|
|
*(i32*)handle_out = fd;
|
2017-07-03 15:43:51 +00:00
|
|
|
result = true;
|
2017-06-30 22:29:34 +00:00
|
|
|
}
|
|
|
|
|
2017-07-18 20:51:44 +00:00
|
|
|
return(result);
|
2017-06-30 22:29:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
Sys_Load_Size_Sig(system_load_size){
|
|
|
|
u32 result = 0;
|
|
|
|
|
2017-11-14 00:22:12 +00:00
|
|
|
i32 fd = *(i32*)&handle;
|
|
|
|
struct stat st = {0};
|
2017-06-30 22:29:34 +00:00
|
|
|
|
2017-11-14 00:22:12 +00:00
|
|
|
if (fstat(fd, &st) == -1){
|
|
|
|
LOGF("unable to stat a file\n");
|
2017-07-01 01:32:35 +00:00
|
|
|
}
|
|
|
|
else{
|
2017-11-14 00:22:12 +00:00
|
|
|
LOGF("file descriptor (%d) has size %d\n", fd, (i32)st.st_size);
|
2017-06-30 22:29:34 +00:00
|
|
|
result = st.st_size;
|
|
|
|
}
|
|
|
|
|
2017-11-14 00:22:12 +00:00
|
|
|
return(result);
|
2017-06-30 22:29:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
Sys_Load_File_Sig(system_load_file){
|
2017-11-14 00:22:12 +00:00
|
|
|
i32 fd = *(i32*)&handle;
|
2017-07-01 01:32:35 +00:00
|
|
|
|
|
|
|
do{
|
2017-06-30 22:29:34 +00:00
|
|
|
ssize_t n = read(fd, buffer, size);
|
2017-11-14 00:22:12 +00:00
|
|
|
if (n == -1){
|
|
|
|
if (errno != EINTR){
|
|
|
|
LOGF("error reading from file descriptor (%d)\n", fd);
|
2017-06-30 22:29:34 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-07-01 01:32:35 +00:00
|
|
|
}
|
|
|
|
else{
|
2017-06-30 22:29:34 +00:00
|
|
|
size -= n;
|
|
|
|
buffer += n;
|
|
|
|
}
|
|
|
|
} while(size);
|
|
|
|
|
2017-11-14 00:22:12 +00:00
|
|
|
return(size == 0);
|
2017-06-30 22:29:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
Sys_Load_Close_Sig(system_load_close){
|
2017-11-14 00:22:12 +00:00
|
|
|
b32 result = true;
|
2017-06-30 22:29:34 +00:00
|
|
|
|
2017-11-14 00:22:12 +00:00
|
|
|
i32 fd = *(i32*)&handle;
|
|
|
|
if (close(fd) == -1){
|
|
|
|
LOGF("error closing file descriptor (%d)\n", fd);
|
|
|
|
result = false;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
LOGF("file descriptor (%d) closed\n", fd);
|
2017-06-30 22:29:34 +00:00
|
|
|
}
|
|
|
|
|
2017-11-14 21:35:17 +00:00
|
|
|
FD_CHECK();
|
|
|
|
|
2017-11-14 00:22:12 +00:00
|
|
|
return(result);
|
2017-06-30 22:29:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
Sys_Save_File_Sig(system_save_file){
|
2017-11-14 00:22:12 +00:00
|
|
|
i32 fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 00640);
|
|
|
|
|
2017-07-03 15:43:51 +00:00
|
|
|
LOGF("%s %d\n", filename, size);
|
2017-11-14 00:22:12 +00:00
|
|
|
if (fd < 0){
|
2017-07-03 15:43:51 +00:00
|
|
|
LOGF("error: open '%s': %s\n", filename, strerror(errno));
|
2017-06-30 22:29:34 +00:00
|
|
|
}
|
|
|
|
else{
|
2017-11-14 00:22:12 +00:00
|
|
|
do{
|
2017-06-30 22:29:34 +00:00
|
|
|
ssize_t written = write(fd, buffer, size);
|
2017-11-14 00:22:12 +00:00
|
|
|
if (written == -1){
|
|
|
|
if (errno != EINTR){
|
2017-07-03 15:43:51 +00:00
|
|
|
LOG("error: write\n");
|
2017-06-30 22:29:34 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-11-14 00:22:12 +00:00
|
|
|
}
|
|
|
|
else{
|
2017-06-30 22:29:34 +00:00
|
|
|
size -= written;
|
|
|
|
buffer += written;
|
|
|
|
}
|
2017-11-14 00:22:12 +00:00
|
|
|
}while(size);
|
2017-06-30 22:29:34 +00:00
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
2017-11-14 00:22:12 +00:00
|
|
|
return(size == 0);
|
2017-06-30 22:29:34 +00:00
|
|
|
}
|
|
|
|
|
2017-07-01 01:32:35 +00:00
|
|
|
//
|
|
|
|
// File System
|
|
|
|
//
|
|
|
|
|
|
|
|
internal
|
|
|
|
Sys_File_Exists_Sig(system_file_exists){
|
|
|
|
int result = 0;
|
|
|
|
char buff[PATH_MAX] = {};
|
|
|
|
|
|
|
|
if (len + 1 > PATH_MAX){
|
|
|
|
LOG("system_directory_has_file: path too long\n");
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
memcpy(buff, filename, len);
|
|
|
|
buff[len] = 0;
|
|
|
|
struct stat st;
|
|
|
|
result = stat(buff, &st) == 0 && S_ISREG(st.st_mode);
|
|
|
|
}
|
|
|
|
|
2017-07-03 15:43:51 +00:00
|
|
|
LOGF("%s: %d\n", buff, result);
|
2017-07-01 01:32:35 +00:00
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
2017-07-18 20:51:44 +00:00
|
|
|
internal b32
|
|
|
|
system_directory_exists(char *path){
|
|
|
|
struct stat st;
|
2017-07-18 21:23:45 +00:00
|
|
|
b32 result = (stat(path, &st) == 0 && S_ISDIR(st.st_mode));
|
2017-07-18 20:51:44 +00:00
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
2017-06-30 22:39:47 +00:00
|
|
|
//
|
|
|
|
// Time
|
|
|
|
//
|
|
|
|
|
|
|
|
internal
|
|
|
|
Sys_Now_Time_Sig(system_now_time){
|
|
|
|
struct timespec spec;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &spec);
|
|
|
|
u64 result = (spec.tv_sec * UINT64_C(1000000)) + (spec.tv_nsec / UINT64_C(1000));
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
2017-06-30 19:08:11 +00:00
|
|
|
// BOTTOM
|
|
|
|
|