Initial commit

This commit is contained in:
2026-04-03 00:22:39 -05:00
commit eca1e8c458
945 changed files with 218160 additions and 0 deletions

44
libsst-os/Makefile Normal file
View File

@@ -0,0 +1,44 @@
# libsst-os/Makefile
# Author: Patrick Baggett <ptbaggett@762studios.com>
# Created: 12/23/2011
#
# Purpose:
#
# Makefile for libsst-os
#
# License:
#
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What The Fuck You Want
# To Public License, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING for more details.
BINNAME := $(DIST)/libsst-os.a
ifeq ($(TARGET),debug)
BINNAME := $(subst .a,_d.a, $(BINNAME))
endif
include sources-$(SUBSYSTEM).mk
OBJ := $(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .c,.o,$(SRC))) obj/$(ARCH)/$(TARGET)/SST_CPUCache_$(ARCH).o
$(shell mkdir -p obj/$(ARCH)/$(TARGET))
$(BINNAME): $(OBJ)
$(AR) cru $@ $+
$(RANLIB) $@
# CLEAN
clean:
@-rm -r -f obj $(DIST)/libsst-os*.a
# *.c files to *.o files
obj/$(ARCH)/$(TARGET)/%.o: %.c
@echo CC $@
@$(CC) $(CFLAGS) -c $*.c -o obj/$(ARCH)/$(TARGET)/$*.o
# *.asm files to *.o files
obj/$(ARCH)/$(TARGET)/%.o: %.asm
@echo ASM $@
@$(ASM) $*.asm -o obj/$(ARCH)/$(TARGET)/$*.o

57
libsst-os/POSIXPrivate.h Normal file
View File

@@ -0,0 +1,57 @@
/*
POSIXPrivate.h
Author: Patrick Baggett <ptb1@762studios.com>
Created: 12/23/2011
Purpose:
Private data structures for POSIX implementation of libsst-os. Not to be distributed
as part of public SDK headers.
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#pragma once
#ifndef _POSIXPRIVATE_H
#define _POSIXPRIVATE_H
/* We *really* want 64-bit support */
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64
#include <pstdint.h>
#include <stdlib.h> /* size_t, malloc(), free()*/
#include <unistd.h>
#include <sys/mman.h> /* mmap(), mprotect(), munmap(), etc. */
/******************************************************************************/
typedef struct SST_File_POSIX
{
int fd;
int isAsync; /* Is this file in async mode */
#ifdef _DEBUG
int nrMmaps; /* Number of outstanding memory maps */
#endif
} SST_File_POSIX;
typedef struct SST_MemoryMap_POSIX
{
uint64_t offset; /* Offset parameter as given to SST_OS_MmapCreate() */
size_t len; /* Length parameter as given to SST_OS_MmapCreate() */
void* base; /* Returned base address from SST_OS_MmapCreate() */
#ifdef _DEBUG
SST_File_POSIX* owner; /* File that created this memory map */
#endif
} SST_MemoryMap_POSIX;
#endif

118
libsst-os/SST_Alloc.c Normal file
View File

@@ -0,0 +1,118 @@
/*
SST_Alloc.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 1/7/2012
Purpose:
Provides portable implementations for various CRT-like memory functions
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include <SST/SST_Alloc.h>
#include <SST/SST_Assert.h>
#include <stdio.h>
#include <pstdint.h>
#include <limits.h>
#define OVERFLOW_MESSAGE "Multiplication overflow in memory allocation"
/*************************************************************************/
void* SST_OS_AlignPtr(void* ptr, size_t boundary)
{
if ((((uintptr_t)ptr) % boundary) == 0)
return ptr;
return (void*)((uintptr_t)ptr + (boundary) - ((uintptr_t)ptr % boundary));
}
/*************************************************************************/
void* SST_OS_AlignedMalloc(size_t bytes, size_t boundary)
{
uintptr_t mask;
uintptr_t addr;
unsigned char delta;
void* base;
unsigned char* backptr;
if(boundary == 0 || boundary > UCHAR_MAX)
return NULL;
mask = (uintptr_t)(boundary - 1);
/* Check if not a power 2 */
if(boundary & mask)
return NULL;
/* Allocate memory with some slack space */
base = malloc(bytes + boundary);
if(base == NULL)
return NULL;
/* Get aligned address. It'll be somewhere in the extra slackspace that we just malloc()'d */
addr = ((uintptr_t)base + boundary - 1) & mask;
/* Address was already aligned...but the free function expects a backtrack amount */
if(addr == (uintptr_t)base)
addr += boundary;
delta = (unsigned char)((addr - (uintptr_t)base) & 0xFF);
backptr = (unsigned char*)(addr-1);
*backptr = delta-1;
return (void*)addr;
}
/*************************************************************************/
void SST_OS_AlignedFree(void* ptr)
{
unsigned char* back = ((unsigned char*)ptr) - 1;
unsigned char delta;
delta = *back;
back = back - delta;
free(back);
}
/*************************************************************************/
void* SST_OS_SafeAlignedMalloc(size_t nelem, size_t elsize, size_t boundary)
{
if(nelem > SIZE_MAX/elsize)
{
SST_OS_RuntimeError(OVERFLOW_MESSAGE);
/* If app just swallows the error, then return NULL */
return NULL;
}
return SST_OS_AlignedMalloc(nelem*elsize, boundary);
}
/*************************************************************************/
void* SST_OS_SafeRealloc(void* ptr, size_t nelem, size_t elsize)
{
if(nelem > SIZE_MAX/elsize)
{
SST_OS_RuntimeError(OVERFLOW_MESSAGE);
/* If app just swallows the error, then return NULL */
return NULL;
}
return realloc(ptr, nelem * elsize);
}

44
libsst-os/SST_Assert.c Normal file
View File

@@ -0,0 +1,44 @@
/*
SST_Assert.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os common assert functions
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include <SST/SST_Assert.h>
#include <stdlib.h> /* NULL */
/*************************************************************************/
SST_AssertHandlerFunc sst_debug_assert_handler = NULL; /* Handler function for debug asserts */
void* sst_debug_assert_handler_arg = NULL; /* Argument to the debug assert */
SST_AssertHandlerFunc sst_runtime_assert_handler = NULL; /* Handler function for runtime asserts */
void* sst_runtime_assert_handler_arg = NULL; /* Argument to the runtime assert */
/*************************************************************************/
void SST_OS_SetDebugAssertHandler(SST_AssertHandlerFunc _func, void *_arg)
{
sst_debug_assert_handler = _func;
sst_debug_assert_handler_arg = _arg;
}
/*************************************************************************/
void SST_OS_SetRuntimeAssertHandler(SST_AssertHandlerFunc _func, void *_arg)
{
sst_runtime_assert_handler = _func;
sst_runtime_assert_handler_arg = _arg;
}

View File

@@ -0,0 +1,74 @@
/*
SST_Assert_Generic.c
Author: Patrick Baggett <ptb1@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os assert functions portable for any system with a C standard library
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include <SST/SST_Assert.h>
#include <stdio.h> /* printf() */
#include <stdlib.h> /* abort() */
/******************************************************************************/
void SST_OS_RuntimeAssertImpl(int condition, const char* condString, const char* msgString, const char* file, const char* func, int line)
{
/* Assume likely success and exit early */
if(condition)
return;
/* Call the runtime handler if we have one */
if (sst_runtime_assert_handler != 0)
if(sst_runtime_assert_handler(msgString, sst_runtime_assert_handler_arg))
return;
printf("The application has reached a runtime assertion failure! This means a serious problem has occurred and the program needs to close.\n\nProgrammer Info:\n\nFile \"%s\", line (%d) in function \"%s()\".\n\nFailed condition: \"%s\"\n\n"
,
file,
line,
func,
condString);
#ifdef _DEBUG
PORTABLE_TRAP();
#else
abort();
#endif
}
/******************************************************************************/
void SST_OS_RuntimeAssertImplNoInfo(int cond, const char* msgString)
{
/* Assume likely success and exit early */
if(cond)
return;
/* Call the runtime handler if we have one */
if (sst_runtime_assert_handler != 0)
if(sst_runtime_assert_handler(msgString, sst_runtime_assert_handler_arg))
return;
printf("The application has reached a runtime assertion failure! This means a serious problem has occurred, and the application needs to close.\n");
#ifdef _DEBUG
PORTABLE_TRAP();
#else
abort();
#endif
}

View File

@@ -0,0 +1,157 @@
/*
SST_Assert_Win32.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os assert functions for Win32 systems (Windows 7 or later)
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#define _CRT_SECURE_NO_WARNINGS /* Shhh, compiler */
#include <SST/SST_Assert.h>
#include "Win32Private.h"
#include <stdio.h> /* sprintf() */
/*************************************************************************/
void SST_OS_RuntimeAssertImpl(int condition, const char* condString, const char* msgString, const char* file, const char* func, int line)
{
UINT flags;
char buf[2048];
int retcode;
/* Assume likely success and exit early */
if(condition)
return;
/* Call the runtime handler if we have one */
if (sst_runtime_assert_handler != 0)
retcode = sst_runtime_assert_handler(msgString, sst_runtime_assert_handler_arg);
else
retcode = 0;
/* See if user handler returned non-zero (i.e. don't raise error) */
if(retcode != 0)
return;
sprintf(buf, "The application has reached a runtime assertion failure! Normally, this means a serious problem, and the program should close.\n\nProgrammer Info:\n\nFile \"%s\", line (%d) in function \"%s()\".\n\nFailed condition: \"%s\"\n\n"
#ifdef _DEBUG
"Terminate application? (Click \"Cancel\" to debug)\n\n"
#endif
,
file,
line,
func,
condString);
#ifdef _DEBUG
flags = MB_YESNOCANCEL | MB_ICONERROR;
#else
flags = MB_OK | MB_ICONERROR;
#endif
retcode = MessageBoxA(NULL, buf, "libSST: Runtime assertion failure!", flags);
#ifdef _DEBUG
switch(retcode)
{
/* Yes -- terminate process */
case IDYES:
ExitProcess((UINT)line);
/* No 'break' -- function never returns */
/* No -- just continue */
case IDNO:
return;
/* Cancel -- debug it */
case IDCANCEL:
PORTABLE_TRAP();
break;
}
#else
/* Ignore return value in release mode, just exit using the line number as the exit code. Since this is non-zero, it should signal to the OS that there was a problem. */
(void)retcode;
ExitProcess((UINT)line);
#endif
}
/*************************************************************************/
void SST_OS_RuntimeAssertImplNoInfo(int cond, const char* msgString)
{
UINT flags;
int retcode;
/* Assume likely success and exit early */
if(cond)
return;
/* Call the runtime handler if we have one */
if (sst_runtime_assert_handler != 0)
retcode = sst_runtime_assert_handler(msgString, sst_runtime_assert_handler_arg);
else
retcode = 0;
/* See if user handler returned non-zero (i.e. don't raise error) */
if(retcode != 0)
return;
#ifdef _DEBUG
flags = MB_YESNOCANCEL | MB_ICONERROR;
#else
flags = MB_OK | MB_ICONERROR;
#endif
retcode = MessageBoxA(NULL,
/* Message */
#ifdef _DEBUG
"The application has reached a runtime assertion failure! Normally, this means a serious problem has occurred, and the program should close.\n\n"
"Terminate application?"
#else /* Release doesn't have an option to not close */
"The application has reached a runtime assertion failure! This means a serious problem has occurred, and the application needs to close."
#endif
,
"libSST: Runtime assertion failure!", flags);
#ifdef _DEBUG
switch(retcode)
{
/* No -- just continue */
case IDNO:
return;
/* Cancel -- debug it */
case IDCANCEL:
PORTABLE_TRAP();
break;
/* Yes -- terminate process */
case IDYES:
break;
}
#else
/* Ignore return value in release mode, just exit. */
(void)retcode;
#endif
/* dead code :( */
ExitProcess(0xdeadc0de);
}

View File

@@ -0,0 +1,41 @@
@ SST_CPUCache_arm.asm
@ Author: Patrick Baggett <ptbaggett@762studios.com>
@ Created: 6/21/2012
@
@ Purpose:
@
@ 32-bit assembly for ARMv6+ CPU cache functions. Assembles with GNU as
@
@ License:
@
@ This program is free software. It comes without any warranty, to
@ the extent permitted by applicable law. You can redistribute it
@ and/or modify it under the terms of the Do What The Fuck You Want
@ To Public License, Version 2, as published by Sam Hocevar. See
@ http://sam.zoy.org/wtfpl/COPYING for more details.
.text
@ ELF symbol names
.global SST_OS_GetCacheLineSize
.global SST_OS_FlushDCRange
.global SST_OS_InvalidateICRange
.global SST_OS_SyncCache
@ uint32_t SST_OS_GetCacheLineSize()
SST_OS_GetCacheLineSize:
bx lr
@ void SST_OS_FlushDCRange(void* base, size_t range)
SST_OS_FlushDCRange:
bx lr
@ void SST_OS_InvalidateICRange(void* base, size_t range)
SST_OS_InvalidateICRange:
bx lr
@ void SST_OS_SyncCache()
SST_OS_SyncCache:
bx lr

View File

@@ -0,0 +1,38 @@
/*
SST_CPUCache_ia64.asm
Author: Patrick Baggett <ptb1@762studios.com>
Created: 4/16/2012
Purpose:
Itanium assembly for CPU cache functions
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
//Functions
.global SST_OS_GetCacheLineSize#
.global SST_OS_FlushDCRange#
.global SST_OS_InvalidateICRange#
.global SST_OS_SyncCache#
.section .text
/* uint32_t SST_OS_GetCacheLineSize() */
.align 32
SST_OS_GetCacheLineSize:
/* SST_OS_InvalidateICRange(void* base, size_t range) */
SST_OS_InvalidateICRange:
SST_OS_FlushDCRange:
/* void SST_OS_SyncCache() */
SST_OS_SyncCache:
br.ret.sptk.many b0;;

View File

@@ -0,0 +1,46 @@
/*
SST_CPUCache_mips.asm
Author: Patrick Baggett <ptb1@762studios.com>
Created: 7/20/2012
Purpose:
32-bit assembly for MIPS CPU cache functions
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/* ELF symbol names */
.global SST_OS_GetCacheLineSize
.global SST_OS_FlushDCRange
.global SST_OS_InvalidateICRange
.global SST_OS_SyncCache
/* uint32_t SST_OS_GetCacheLineSize() */
SST_OS_GetCacheLineSize:
jr $ra
li $v0, 64
/* SST_OS_InvalidateICRange(void* base, size_t range) */
SST_OS_InvalidateICRange:
jr $ra
nop
SST_OS_FlushDCRange:
sync
jr $ra
nop
/* void SST_OS_SyncCache() */
SST_OS_SyncCache:
sync
jr $ra
nop

View File

@@ -0,0 +1,41 @@
/*
SST_CPUCache_ppc.asm
Author: Patrick Baggett <ptb1@762studios.com>
Created: 7/20/2012
Purpose:
32-bit assembly for Power Architecture CPU cache functions
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/* ELF symbol names */
.global SST_OS_GetCacheLineSize
.global SST_OS_FlushDCRange
.global SST_OS_InvalidateICRange
.global SST_OS_SyncCache
/* uint32_t SST_OS_GetCacheLineSize() */
SST_OS_GetCacheLineSize:
li r3, 64
blr
/* SST_OS_InvalidateICRange(void* base, size_t range) */
SST_OS_InvalidateICRange:
SST_OS_FlushDCRange:
blr
/* void SST_OS_SyncCache() */
SST_OS_SyncCache:
sync
isync
blr

View File

@@ -0,0 +1,50 @@
/*
SST_CPUCache_sparc.asm
Author: Patrick Baggett <ptb1@762studios.com>
Created: 12/23/2011
Purpose:
32-bit assembly for SPARCv9 CPU cache functions
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/* ELF symbol names */
.global SST_OS_GetCacheLineSize
.global SST_OS_FlushDCRange
.global SST_OS_InvalidateICRange
.global SST_OS_SyncCache
/* uint32_t SST_OS_GetCacheLineSize() */
SST_OS_GetCacheLineSize:
retl
or %g0, 64, %o0 /* kludge: it's 64. */
/* SST_OS_InvalidateICRange(void* base, size_t range) */
SST_OS_InvalidateICRange:
SST_OS_FlushDCRange:
add %o0, %o1, %o2 /* %o2 = end address */
1:
flush %o0
cmp %o0, %o2
bcs %icc,1b /* branch on less than (unsigned) */
add %o0, 8, %o0 /* FLUSH insn flushes a double word at a time */
retl
nop
/* void SST_OS_SyncCache() */
SST_OS_SyncCache:
membar #Sync
retl
nop

View File

@@ -0,0 +1,49 @@
/*
SST_CPUCache_sparc64.asm
Author: Patrick Baggett <ptb1@762studios.com>
Created: 12/23/2011
Purpose:
64-bit assembly for SPARCv9 CPU cache functions
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
.global SST_OS_GetCacheLineSize
.global SST_OS_FlushDCRange
.global SST_OS_InvalidateICRange
.global SST_OS_SyncCache
/* uint32_t SST_OS_GetCacheLineSize() */
SST_OS_GetCacheLineSize:
retl
or %g0, 64, %o0 /* kludge: it's 64. */
/* SST_OS_InvalidateICRange(void* base, size_t range) */
SST_OS_InvalidateICRange:
SST_OS_FlushDCRange:
add %o0, %o1, %o2 /* %o2 = end address */
1:
flush %o0
cmp %o0, %o2
bcs %xcc,1b /* branch on less than (unsigned) */
add %o0, 8, %o0 /* FLUSH insn flushes a double word at a time */
retl
nop
/* void SST_OS_SyncCache() */
SST_OS_SyncCache:
membar #Sync
retl
nop

View File

@@ -0,0 +1,76 @@
; SST_CPUCache_x86-64-win64.asm
; Author: Patrick Baggett <ptbaggett@762studios.com>
; Created: 12/23/2011
;
; Purpose:
;
; 64-bit assembly for x86 CPU cache functions for the Microsoft x64 ABI. Assembles with YASM 1.1/NASM 2.0+
;
; License:
;
; This program is free software. It comes without any warranty, to
; the extent permitted by applicable law. You can redistribute it
; and/or modify it under the terms of the Do What The Fuck You Want
; To Public License, Version 2, as published by Sam Hocevar. See
; http://sam.zoy.org/wtfpl/COPYING for more details.
; Win64 and UNIX calling conventions differ for x64-64. I know, it's absurd.
; Because of this, there are separate implementation for Win64 and x64-64 UNIX (Linux, *BSD, Solaris, MacOS X, etc.)
; Here is the break down:
;
; REGISTER | Win64 | UNIX
;-----------+-----------+----------
;rax | Retval | Retval
;rsi | Not used | 1st arg
;rdi | Not used | 2nd arg
;rcx | 1st arg | 3rd arg
;rdx | 2nd arg | 4th arg
;r8 | 3rd arg | 5th arg
;r9 | 4th arg | 6th arg
[bits 64]
[segment .text]
; Win64 symbol names
[global SST_OS_GetCacheLineSize]
[global SST_OS_FlushDCRange]
[global SST_OS_InvalidateICRange]
[global SST_OS_SyncCache]
;uint32_t SST_OS_GetCacheLineSize()
SST_OS_GetCacheLineSize:
push rbx
mov eax, 0x80000006 ;Cache info command
cpuid
movzx rax, cl ;ECX bits 0-7 = L2 cache line size (TODO: what about L1?)
pop rbx
ret
;SST_OS_InvalidateICRange(void* base, size_t range)
SST_OS_InvalidateICRange:
;A jmp instruction is sufficient. x86 CPUs have self-snooping caches.
jmp do_serialize
do_serialize:
ret
; void SST_OS_SyncCache()
SST_OS_SyncCache:
mfence
ret
;void SST_OS_FlushDCRange(void* base, size_t range)
SST_OS_FlushDCRange:
call SST_OS_GetCacheLineSize ;Get the cache line size
dc_flush_more2: ;do {
clflush [rsi]
add rsi, rax ;base += cache_line_size
sub rdi, rax ;range -= cache_line_size
cmp rcx, 0
jg dc_flush_more2 ; } while(range > 0)
ret

View File

@@ -0,0 +1,78 @@
; SST_CPUCache_x86-64.asm
; Author: Patrick Baggett <ptbaggett@762studios.com>
; Created: 12/23/2011
;
; Purpose:
;
; 64-bit assembly for x86 CPU cache functions for the SysV ABI. Assembles with YASM 1.1/NASM 2.0+
;
; License:
;
; This program is free software. It comes without any warranty, to
; the extent permitted by applicable law. You can redistribute it
; and/or modify it under the terms of the Do What The Fuck You Want
; To Public License, Version 2, as published by Sam Hocevar. See
; http://sam.zoy.org/wtfpl/COPYING for more details.
; Win64 and UNIX calling conventions differ for x64-64. I know, it's absurd.
; Because of this, there are separate implementation for Win64 and x64-64 UNIX (Linux, *BSD, Solaris, MacOS X, etc.)
; Here is the break down:
;
; REGISTER | Win64 | UNIX
;-----------+-----------+----------
;rax | Retval | Retval
;rsi | Not used | 1st arg
;rdi | Not used | 2nd arg
;rcx | 1st arg | 3rd arg
;rdx | 2nd arg | 4th arg
;r8 | 3rd arg | 5th arg
;r9 | 4th arg | 6th arg
[bits 64]
[segment .text]
; ELF symbol names
[global SST_OS_GetCacheLineSize]
[global SST_OS_FlushDCRange]
[global SST_OS_InvalidateICRange]
[global SST_OS_SyncCache]
;uint32_t SST_OS_GetCacheLineSize()
;no args, so win64 and unix abis are the same
SST_OS_GetCacheLineSize:
push rbx
mov eax, 0x80000006 ;Cache info command
cpuid
movzx rax, cl ;ECX bits 0-7 = L2 cache line size (TODO: what about L1?)
pop rbx
ret
;SST_OS_InvalidateICRange(void* base, size_t range)
SST_OS_InvalidateICRange:
;A jmp instruction is sufficient. x86 CPUs have self-snooping caches.
jmp do_serialize
do_serialize:
ret
; void SST_OS_SyncCache()
SST_OS_SyncCache:
mfence
ret
;void SST_OS_FlushDCRange(void* base, size_t range)
SST_OS_FlushDCRange:
call SST_OS_GetCacheLineSize ;Get the cache line size
dc_flush_more1: ;do {
clflush [rcx]
add rcx, rax ;base += cache_line_size
sub rdx, rax ;range -= cache_line_size
cmp rcx, 0
jg dc_flush_more1 ; } while(range > 0)
ret

View File

@@ -0,0 +1,77 @@
; SST_CPUCache_x86.asm
; Author: Patrick Baggett <ptbaggett@762studios.com>
; Created: 12/23/2011
;
; Purpose:
;
; 32-bit assembly for x86 CPU cache functions. Assembles with YASM 1.1/NASM 2.0+
;
; License:
;
; This program is free software. It comes without any warranty, to
; the extent permitted by applicable law. You can redistribute it
; and/or modify it under the terms of the Do What The Fuck You Want
; To Public License, Version 2, as published by Sam Hocevar. See
; http://sam.zoy.org/wtfpl/COPYING for more details.
[bits 32]
[segment .text]
; Win32 symbol names
[global _SST_OS_GetCacheLineSize]
[global _SST_OS_FlushDCRange]
[global _SST_OS_InvalidateICRange]
[global _SST_OS_SyncCache]
; ELF symbol names
[global SST_OS_GetCacheLineSize]
[global SST_OS_FlushDCRange]
[global SST_OS_InvalidateICRange]
[global SST_OS_SyncCache]
;uint32_t SST_OS_GetCacheLineSize()
_SST_OS_GetCacheLineSize:
SST_OS_GetCacheLineSize:
push ebx
mov eax, 0x80000006 ;Cache info command
cpuid
movzx eax, cl ;ECX bits 0-7 = L2 cache line size (TODO: what about L1?)
pop ebx
ret
;void SST_OS_FlushDCRange(void* base, size_t range)
_SST_OS_FlushDCRange:
SST_OS_FlushDCRange:
call SST_OS_GetCacheLineSize ;Get the cache line size
mov edx, [esp+4] ;edx = base
mov ecx, [esp+8] ;ecx = range (in bytes)
dc_flush_more: ;do {
clflush [edx]
add edx, eax ;base += cache_line_size
sub ecx, eax ;range -= cache_line_size
cmp ecx, 0
jg dc_flush_more ; } while(range > 0)
ret
;SST_OS_InvalidateICRange(void* base, size_t range)
_SST_OS_InvalidateICRange:
SST_OS_InvalidateICRange:
;A jmp instruction is sufficient. x86 CPUs have self-snooping caches.
jmp do_serialize
do_serialize:
ret
; void SST_OS_SyncCache()
_SST_OS_SyncCache:
SST_OS_SyncCache:
mfence
ret

94
libsst-os/SST_CPU_POSIX.c Normal file
View File

@@ -0,0 +1,94 @@
/*
SST_CPU_POSIX.c
Author: Patrick Baggett <ptb1@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os CPU querying functions for POSIX systems
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/*
The POSIX doesn't actually provide much in the terms of CPU
querying. Other source files provide specific operating systems
implementations (e.g: Linux, Solaris, ...)
*/
#include "POSIXPrivate.h"
#include <SST/SST_CPU.h>
#include <SST/SST_Assert.h>
/******************************************************************************/
int SST_OS_GetNumberCPUChips()
{
/* 0 -> no information available */
return 0;
}
/******************************************************************************/
int SST_OS_GetNumberPhysicalCPUs(void)
{
/* 0 -> no information available */
return 0;
}
/******************************************************************************/
int SST_OS_GetNumberLogicalCPUs(void)
{
return (int)sysconf(_SC_NPROCESSORS_ONLN);
}
/******************************************************************************/
int SST_OS_MapPhysicalToLogicalCPU(int physCpuId, int* logCpuIds)
{
(void)physCpuId;
(void)logCpuIds;
/* 0 -> API not available */
return 0;
}
/******************************************************************************/
int SST_OS_GetCPUAffinity(unsigned char* cpuMaskReturn, unsigned int cpuMaskSize)
{
SST_OS_DebugAssert(cpuMaskReturn != NULL, "CPU mask may not be NULL");
(void)cpuMaskReturn;
(void)cpuMaskSize;
return 0; /* NYI */
}
/******************************************************************************/
int SST_OS_SetCPUAffinity(const unsigned char* cpuMask, unsigned int cpuMaskSize)
{
SST_OS_DebugAssert(cpuMask != NULL, "CPU mask may not be NULL");
(void)cpuMask;
(void)cpuMaskSize;
return 0; /* NYI */
}
/******************************************************************************/
void SST_OS_SetPreferredCPU(int logCpuId)
{
(void)logCpuId;
/* Hint ignored */
return;
}

354
libsst-os/SST_CPU_Win32.c Normal file
View File

@@ -0,0 +1,354 @@
/*
SST_CPU_Win32.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os CPU querying functions for Win32 systems (Windows 7 or later)
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include "Win32Private.h"
#include <malloc.h> /* _alloca() */
#include <SST/SST_CPU.h>
#include <SST/SST_Assert.h>
/*
SUPPORT FOR > 64 CPUS
----------------------
This code does its best to be compatible with large numbers of logical CPUs. Processor groups are
a bit weird, see MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/dd405503(v=vs.85).aspx)
*/
/*************************************************************************/
static const uint8_t popbits[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
/*************************************************************************/
/* popcount of an 8-bit value */
static uint8_t popcount8(uint8_t v)
{
return popbits[v & 0x0Fu] + popbits[v>>4];
}
/*************************************************************************/
/* popcount on the Win32 KAFFINITY value (64-bit value) */
static int popcount(KAFFINITY mask)
{
int count = 0, i;
for(i=0; i<sizeof(KAFFINITY); i++)
{
/* No more bits set? */
if(!mask)
break;
count += popcount8(mask & 0xFF);
mask >>= 8;
}
return count;
}
/*************************************************************************/
int SST_OS_GetNumberCPUChips()
{
DWORD length = 0;
SYSTEM_LOGICAL_PROCESSOR_INFORMATION* relat;
DWORD nr;
int nrChips = 0;
/* Query data structure size */
GetLogicalProcessorInformation(NULL, &length);
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return -1;
/* Really get the info this time */
relat = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION*)_alloca((size_t)length);
if(GetLogicalProcessorInformation(relat, &length) == FALSE)
return -2;
/* Scan list */
nr = length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
while(nr > 0)
{
if(relat->Relationship == RelationProcessorPackage)
nrChips++;
relat++;
nr--;
}
return nrChips;
}
/*************************************************************************/
int SST_OS_GetNumberPhysicalCPUs(void)
{
DWORD length = 0;
char* ptr, *end;
int nrCores = 0;
/* Query data structure size */
GetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &length);
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return -1;
/* Really get the info this time */
ptr = (char*)_alloca((size_t)length);
end = ptr + length;
if(GetLogicalProcessorInformationEx(
RelationProcessorCore,
(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)ptr,
&length) == FALSE)
return -2;
while(ptr < end)
{
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)ptr;
nrCores++;
ptr += (size_t)info->Size;
}
return nrCores;
}
/*************************************************************************/
int SST_OS_GetNumberLogicalCPUs(void)
{
DWORD length = 0;
char* ptr, *end;
int nrThreads = 0;
/* Query data structure size */
GetLogicalProcessorInformationEx(RelationProcessorPackage, NULL, &length);
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return -1;
/* Really get the info this time */
ptr = (char*)_alloca((size_t)length);
end = ptr + length;
if(GetLogicalProcessorInformationEx(
RelationProcessorPackage,
(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)ptr,
&length) == FALSE)
return -2;
while(ptr < end)
{
WORD i;
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)ptr;
for(i=0; i<info->Processor.GroupCount; i++)
nrThreads += popcount(info->Processor.GroupMask[i].Mask);
ptr += info->Size;
}
return nrThreads;
}
/*************************************************************************/
int SST_OS_MapPhysicalToLogicalCPU(int physCpuId, int* logCpuIds)
{
DWORD length = 0;
char* ptr, *end;
WORD i;
int j;
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* info;
SST_OS_DebugAssert(logCpuIds != NULL, "The return array for logical CPUs may not be NULL");
/* Query data structure size */
GetLogicalProcessorInformationEx(RelationProcessorCore, NULL, &length);
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return -2;
/* Really get the info this time */
ptr = (char*)_alloca((size_t)length);
end = ptr + length;
if(GetLogicalProcessorInformationEx(
RelationProcessorCore,
(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)ptr,
&length) == FALSE)
return -3;
info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)ptr;
#ifdef _DEBUG
{
/* Figure out how many elements in this array */
int nr = (int)(length / info->Size);
/* Bounds checking */
SST_OS_DebugAssert(!(physCpuId >= nr), "Array too small to contain logical CPUs. Use SST_OS_GetNumberLogicalCPUs() to determine correct size");
}
#endif
/* This union is large, so we can't just do info[index], we have to do
'base_address + size * index'. Ugly, but necessary. */
info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(ptr + (size_t)(info->Size*physCpuId));
j = 0; /* j = number of logical CPUs mapped */
for(i=0; i<info->Processor.GroupCount; i++)
{
/* Figure out base logical CPU ID for processor group. Usually 64 CPUs / group. */
int groupbase = (int)(info->Processor.GroupMask[i].Group * 8 * sizeof(KAFFINITY));
size_t k;
KAFFINITY mask = info->Processor.GroupMask[i].Mask;
/*
Algorithm: Each GROUP_AFFINITY structure has a mask. Scan through it and
if bit 'k' is set, then add 'k+groupbase' to the array.
*/
/* Scan through bits and add logical CPUs */
for(k=0; k<(8 * sizeof(KAFFINITY)); k++)
{
/* No more bits set */
if(!mask)
break;
/* Is this bit set? */
if(mask & 1)
{
/* Add the logical CPU to the array */
logCpuIds[j] = (int)k + groupbase;
j++;
}
/* Next bit... */
mask >>= 1;
}
}
/* Return the number of logical CPUs written to logCpuIds[] */
return j;
}
/*************************************************************************/
int SST_OS_GetCPUAffinity(unsigned char* cpuMaskReturn, unsigned int cpuMaskSize)
{
WORD maxGroup;
GROUP_AFFINITY aff;
SST_OS_DebugAssert(cpuMaskReturn != NULL, "CPU mask may not be NULL");
SST_OS_DebugAssert(cpuMaskSize > 0, "CPU mask may not be zero");
/* Calculate the maximum number of groups that can be stored using the space provided */
maxGroup = (WORD)(cpuMaskSize / sizeof(KAFFINITY));
if(cpuMaskSize % sizeof(KAFFINITY))
maxGroup += 1;
if(maxGroup == 0)
return -1;
memset(cpuMaskReturn, 0, cpuMaskSize);
GetThreadGroupAffinity(GetCurrentThread(), &aff);
/* Ensure the real processor group doesn't exceed provided space */
if(aff.Group < maxGroup)
{
uint32_t byteOffset = aff.Group * sizeof(KAFFINITY); /* i.e. where to begin in cpuMaskReturn[] */
uint32_t bytesLeft = cpuMaskSize - byteOffset; /* i.e. how many bytes are left */
uint32_t i;
KAFFINITY mask = aff.Mask;
unsigned char* maskReturn = cpuMaskReturn + byteOffset;
for(i=0; i<bytesLeft; i++)
{
if(!mask)
break;
maskReturn[i] = (uint8_t)(mask & 0xFF);
mask >>= 8;
}
}
return 1;
}
/*************************************************************************/
int SST_OS_SetCPUAffinity(const unsigned char* cpuMask, unsigned int cpuMaskSize)
{
uint8_t groupPopCount[4096/(sizeof(KAFFINITY) * 8)];
KAFFINITY groupMask[4096/(sizeof(KAFFINITY) * 8)];
uint8_t lowest = UINT8_MAX;
uint8_t lowestGroup = 0;
unsigned int i;
GROUP_AFFINITY aff;
SST_OS_DebugAssert(cpuMask != NULL, "CPU mask may not be NULL");
/* Windows only allows a thread to be a member of a single processor group, which makes sense
when you consider that migrating threads across NUMA nodes is a bad idea. Here, we select the
processor group that has the fewest bits set (except for 0...) */
if(cpuMaskSize > 4096) /* Disallow arbitrarily large masks. 4096 processors is fine, really */
cpuMaskSize = 4096;
memset(groupPopCount, 0, sizeof(groupPopCount));
memset(groupMask, 0, sizeof(groupMask));
/* Operate on each byte */
for(i=0; i<cpuMaskSize; i++)
{
uint8_t groupIndex = (uint8_t)(i / sizeof(KAFFINITY)); /* i is in bytes, sizeof() is in bytes */
uint8_t groupByte = (uint8_t)(i % 8);
/* Sum all popcount8() of the bytes that make up a processor group's mask */
groupPopCount[groupIndex] += popcount8(cpuMask[i]);
/* OR the 8-bit mask into KAFFINITY values (essentially merge them) */
groupMask[groupIndex] |= (KAFFINITY)cpuMask[i] << (KAFFINITY)(groupByte * 8);
/* Record the smallest group that is not 0 */
if(groupPopCount[groupIndex] > 0 && groupPopCount[groupIndex] < lowest)
lowest = groupIndex;
}
aff.Group = (WORD)((uint16_t)lowestGroup);
aff.Mask = groupMask[lowestGroup];
SetThreadGroupAffinity(GetCurrentThread(), &aff, NULL);
return 1;
}
/*************************************************************************/
void SST_OS_SetPreferredCPU(int logCpuId)
{
PROCESSOR_NUMBER ideal;
SST_OS_DebugAssert(logCpuId < SST_OS_GetNumberLogicalCPUs(), "Logical CPU ID is out of range");
ideal.Group = (WORD)logCpuId / (WORD)(sizeof(KAFFINITY)*8);
ideal.Number = (WORD)logCpuId % (WORD)(sizeof(KAFFINITY)*8);
ideal.Reserved = 0;
SetThreadIdealProcessorEx(GetCurrentThread(), &ideal, NULL);
}

View File

@@ -0,0 +1,77 @@
/*
SST_DynLib_POSIX.c
Author: Patrick Baggett <ptb1@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os dynamic linking functions for POSIX systems
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include <SST/SST_DynLib.h>
#include <SST/SST_Assert.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <string.h>
/******************************************************************************/
SST_DynLib SST_OS_LoadDynLib(const char* path)
{
SST_OS_DebugAssert(path != NULL, "Path may not be NULL");
return (SST_DynLib)dlopen(path, RTLD_LAZY);
}
/******************************************************************************/
SST_DynLibFunc SST_OS_GetLibSymbol(SST_DynLib lib, const char* symbol)
{
uintptr_t tmp;
SST_OS_DebugAssert(lib != NULL, "Library may not be NULL");
SST_OS_DebugAssert(symbol != NULL, "Library may not be NULL");
tmp = (uintptr_t)dlsym((void*)lib, symbol);
return (SST_DynLibFunc)tmp;
}
/******************************************************************************/
void SST_OS_CloseDynLib(SST_DynLib lib)
{
SST_OS_DebugAssert(lib != NULL, "Library may not be NULL");
dlclose((void*)lib);
}
/******************************************************************************/
int SST_OS_DynLibName(char* libnameOut, const char* libnameIn)
{
SST_OS_DebugAssert(libnameIn != NULL, "Library name may not be NULL");
if(libnameOut == NULL)
return 3+(int)strlen(libnameIn)+3; /* strlen("lib")+strlen(libnameIn)+strlen(".so") */
libnameOut[0] = 'l'; /* strcpy(libnameOut, "lib") */
libnameOut[1] = 'i';
libnameOut[2] = 'b';
strcpy(libnameOut+3, libnameIn);
strcat(libnameOut, ".so");
return 0;
}

View File

@@ -0,0 +1,66 @@
/*
SST_DynLib_Win32.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os dynamic linking functions for Win32 systems (Windows 7 or later)
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include "Win32Private.h"
#include <SST/SST_Assert.h>
#include <SST/SST_DynLib.h>
#include <string.h>
/*************************************************************************/
SST_DynLib SST_OS_LoadDynLib(const char* path)
{
SST_OS_DebugAssert(path != NULL, "Path may not be NULL");
return (SST_DynLib)LoadLibraryExA(path, NULL, 0);
}
/*************************************************************************/
SST_DynLibFunc SST_OS_GetLibSymbol(SST_DynLib lib, const char* symbol)
{
SST_OS_DebugAssert(lib != NULL, "Library may not be NULL");
SST_OS_DebugAssert(symbol != NULL, "Library may not be NULL");
return (SST_DynLibFunc)GetProcAddress((HMODULE)lib, symbol);
}
/*************************************************************************/
void SST_OS_CloseDynLib(SST_DynLib lib)
{
SST_OS_DebugAssert(lib != NULL, "Library may not be NULL");
FreeLibrary((HMODULE)lib);
}
/*************************************************************************/
int SST_OS_DynLibName(char* libnameOut, const char* libnameIn)
{
SST_OS_DebugAssert(libnameIn != NULL, "Library name may not be NULL");
if(libnameOut == NULL)
return (int)strlen(libnameIn)+4; /* +strlen(".dll") */
strcpy(libnameOut, libnameIn);
strcat(libnameOut, ".dll");
return 0;
}

70
libsst-os/SST_Endian.c Normal file
View File

@@ -0,0 +1,70 @@
/*
SST_Endian.c
Author: Chris Ertel <crertel@762studios.com>
Created: 1/16/2012
Purpose:
libsst-os endian and byte reordering routines.
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include <SST/SST_Endian.h>
#include <pstdint.h>
static SST_ByteOrder machineByteOrder;
void __libsst_init_endian()
{
const uint16_t testSeq = 0x55FE;
const uint8_t* c = (const uint8_t*)&testSeq;
if(c[0] == 0x55)
machineByteOrder = SST_BIG_ENDIAN;
else
machineByteOrder = SST_LITTLE_ENDIAN;
}
SST_ByteOrder SST_OS_GetHostEndianness( void )
{
return machineByteOrder;
}
uint16_t SST_OS_ByteSwap16( uint16_t _toSwap)
{
return (_toSwap >> 8) | (_toSwap << 8);
}
uint32_t SST_OS_ByteSwap32( uint32_t _toSwap)
{
uint32_t a = (_toSwap & 0x000000ff);
uint32_t b = (_toSwap & 0x0000ff00) >> 8;
uint32_t c = (_toSwap & 0x00ff0000) >> 16;
uint32_t d = (_toSwap & 0xff000000) >> 24;
uint32_t ret = (a << 24) | (b << 16) | (c << 8) | (d);
return ret;
}
uint64_t SST_OS_ByteSwap64( uint64_t _toSwap)
{
uint64_t a = (_toSwap & 0x00000000000000ffull);
uint64_t b = (_toSwap & 0x000000000000ff00ull) >> 8;
uint64_t c = (_toSwap & 0x0000000000ff0000ull) >> 16;
uint64_t d = (_toSwap & 0x00000000ff000000ull) >> 24;
uint64_t e = (_toSwap & 0x000000ff00000000ull) >> 32;
uint64_t f = (_toSwap & 0x0000ff0000000000ull) >> 40;
uint64_t g = (_toSwap & 0x00ff000000000000ull) >> 48;
uint64_t h = (_toSwap & 0xff00000000000000ull) >> 56;
uint64_t ret = (a << 56) | (b << 48) | (c << 40) | (d << 32) | (e << 24) | (f << 16) | (g << 8) | h;
return ret;
}

View File

@@ -0,0 +1,191 @@
/*
SST_FileSys_POSIX.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 3/31/2012
Purpose:
libsst-os file system querying for POSIX systems
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include <SST/SST_FileSys.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
/* In order to get alloca() on Solaris, <alloca.h> is needed */
#if defined(__SUNPRO_C)
#include <alloca.h>
#endif
/* No PATH_MAX symbol */
#if !defined(PATH_MAX)
#if defined(_POSIX_PATH_MAX) &&
#define PATH_MAX _POSIX_PATH_MAX
#else
#define PATH_MAX 256 /* This is what _POSIX_PATH_MAX must be according to POSIX */
#endif
#endif
typedef struct SST_Dir_POSIX
{
char* canonPath;
size_t canonPathLen;
DIR* dirp;
} SST_Dir_POSIX;
SST_Dir SST_OS_OpenDirectory(const char* path)
{
size_t len;
char* canonPath;
SST_Dir_POSIX* dh;
DIR* dirp;
/* Ensure no trailing slash */
len = strlen(path);
if(len == 0 || path[len-1] == '/')
return NULL;
/* Out of memory? */
canonPath = (char*)malloc(PATH_MAX);
if(!canonPath)
return NULL;
/* Allocate directory handle */
dh = (SST_Dir_POSIX*)malloc(sizeof(SST_Dir_POSIX));
if(!dh)
{
free(canonPath);
return NULL;
}
/* Remove garbage "." and ".." from path, get canonical form */
if(!realpath(path, canonPath))
{
free(canonPath);
free(dh);
return NULL;
}
/* Attempt to open directory */
dirp = opendir(canonPath);
if(!dirp)
{
free(canonPath);
free(dh);
return NULL;
}
dh->canonPathLen = strlen(canonPath);
dh->canonPath = canonPath;
dh->dirp = dirp;
return (SST_Dir)dh;
}
int SST_OS_ReadNextDirectoryEntry(SST_Dir dir, SST_FileInfo* fileInfoReturn)
{
SST_Dir_POSIX* dh = (SST_Dir_POSIX*)dir;
struct dirent* ent;
size_t len;
char* tmp;
struct stat statbuf;
/* Read next directory entry */
ent = readdir(dh->dirp);
if(!ent)
return 0;
/* Ignore "." and ".." */
if(strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
return SST_OS_ReadNextDirectoryEntry(dir, fileInfoReturn);
len = strlen(ent->d_name);
if(len >= SST_FILENAME_MAX)
len = SST_FILENAME_MAX-1;
memcpy(fileInfoReturn->name, ent->d_name, len);
fileInfoReturn->name[len] = 0;
fileInfoReturn->nameLen = len;
tmp = (char*)alloca(dh->canonPathLen + len + 2); /* +2 because of "/" character and NULL */
/* Construct `canonPath` + '/' + `ent->d_name` + '\0' */
memcpy(tmp, dh->canonPath, dh->canonPathLen);
tmp[dh->canonPathLen] = '/';
memcpy(&tmp[dh->canonPathLen+1], ent->d_name, len);
tmp[dh->canonPathLen+1+len] = '\0';
if(stat(tmp, &statbuf) == 0)
{
/* Save result */
fileInfoReturn->isDir = S_ISDIR(statbuf.st_mode);
fileInfoReturn->size = (fileInfoReturn->isDir ? 0 : (size_t)statbuf.st_size);
}
else /* can't stat() file, so not really much to say about it */
{
fileInfoReturn->isDir = 0;
fileInfoReturn->size = 0;
}
return (ent != NULL);
}
void SST_OS_CloseDirectory(SST_Dir dir)
{
SST_Dir_POSIX* dh = (SST_Dir_POSIX*)dir;
closedir(dh->dirp);
free(dh->canonPath);
free(dh);
}
int SST_OS_CreateDirectory(const char* dir)
{
/* Make a directory for anyone to read/write. */
if(mkdir(dir, 0777) == 0)
return 0; /* Success */
if(errno == EEXIST)
{
/* This could refer to a file by the same name, so check to
see if it is really a directory. */
struct stat statbuf;
if(stat(dir, &statbuf) == 0)
{
/* It really is a directory. Return positive to signal
that the directory already exists. */
if(S_ISDIR(statbuf.st_mode))
return 1;
}
}
/* Other error -> failure */
return -1;
}
/******************************************************************************/
int SST_OS_RemoveDirectory(const char* dir)
{
return (rmdir(dir) == 0);
}

View File

@@ -0,0 +1,164 @@
/*
SST_FileSys_Win32.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 3/29/2012
Purpose:
libsst-os file system querying for Win32
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include <SST/SST_FileSys.h>
#include <windows.h>
#include <string.h>
/*************************************************************************/
typedef struct SST_Dir_Win32
{
HANDLE hFind;
WIN32_FIND_DATAA data;
int once;
} SST_Dir_Win32;
/*************************************************************************/
/* Copy data from WIN32_FILE_DATAA structure to SST_FileInfo structure */
static void copyWin32FindData(SST_FileInfo* info, const WIN32_FIND_DATAA* data)
{
size_t len = strlen(data->cFileName);
if(len >= SST_FILENAME_MAX)
len = SST_FILENAME_MAX-1;
memcpy(info->name, data->cFileName, len);
info->name[len] = '\0';
info->size = (((uint64_t)data->nFileSizeHigh) << (8*sizeof(uint32_t))) | ((uint64_t)data->nFileSizeLow);
info->nameLen = len;
info->isDir = (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
}
/*************************************************************************/
SST_Dir SST_OS_OpenDirectory(const char* path)
{
char findPath[MAX_PATH];
size_t len = strlen(path);
SST_Dir_Win32* win32dir;
/* Don't allow paths to end with a trailing slash */
if(path[len-1] == '/' || path[len-1] == '\\')
return NULL;
if(len > MAX_PATH-3)
len = MAX_PATH-3;
/* Append "/" and "*" to the end */
memcpy(findPath, path, len);
findPath[len] = '/';
findPath[len+1] = '*';
findPath[len+2] = '\0';
/* Allocate structure to use */
win32dir = (SST_Dir_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_Dir_Win32));
if(win32dir == NULL)
return (SST_Dir)NULL;
/* Attempt to find the first file */
win32dir->hFind = FindFirstFileA(findPath, &win32dir->data);
win32dir->once = 1;
/* Failed? */
if(win32dir->hFind == INVALID_HANDLE_VALUE)
{
/* FindFirstFile() returns ERROR_FILE_NOT_FOUND when no files are found.
If we didn't get that, then return NULL */
if(GetLastError() != ERROR_FILE_NOT_FOUND)
{
HeapFree(GetProcessHeap(), 0, (void*)win32dir);
return NULL;
}
}
return (SST_Dir)win32dir;
}
/*************************************************************************/
int SST_OS_ReadNextDirectoryEntry(SST_Dir dir, SST_FileInfo* fileInfoReturn)
{
SST_Dir_Win32* win32dir = (SST_Dir_Win32*)dir;
int result = 0;
/* Check if call to FindFirstFileA() returned 0 files found */
if(win32dir->hFind != INVALID_HANDLE_VALUE)
{
/* FindFirstFileA() copies the first file data automatically, so use the first time */
if(win32dir->once)
{
/* NOTE: data already copied to win32dir->data when FindFirstFileA() was called */
win32dir->once = 0;
result = 1;
}
else
result = FindNextFileA(win32dir->hFind, &win32dir->data);
/* If we have file data to copy, then do so now */
if(result)
{
if(strcmp(win32dir->data.cFileName, ".") == 0 || strcmp(win32dir->data.cFileName, "..") == 0)
return SST_OS_ReadNextDirectoryEntry(dir, fileInfoReturn);
else
copyWin32FindData(fileInfoReturn, &win32dir->data);
}
}
return result;
}
/*************************************************************************/
void SST_OS_CloseDirectory(SST_Dir dir)
{
SST_Dir_Win32* win32dir = (SST_Dir_Win32*)dir;
/* Close the handle if not invalid */
if(win32dir->hFind != INVALID_HANDLE_VALUE)
FindClose(win32dir->hFind);
/* Return heap memory */
HeapFree(GetProcessHeap(), 0, (void*)win32dir);
}
/*************************************************************************/
int SST_OS_CreateDirectory(const char* dir)
{
if(CreateDirectoryA(dir, NULL) == FALSE)
{
if(GetLastError() == ERROR_ALREADY_EXISTS)
return 1; /* positive == already exists */
else
return -1; /* negative == error */
}
return 0; /* zero == success */
}
/*************************************************************************/
int SST_OS_RemoveDirectory(const char* dir)
{
return (int)RemoveDirectory(dir);
}

350
libsst-os/SST_File_POSIX.c Normal file
View File

@@ -0,0 +1,350 @@
/*
SST_File_POSIX.c
Author: Patrick Baggett <ptb1@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os file I/O for POSIX platforms
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include "POSIXPrivate.h"
#include <SST/SST_File.h>
#include <SST/SST_Assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/******************************************************************************/
SST_File SST_OS_OpenFile(const char* path, uint32_t mode)
{
int flags;
int fd;
SST_File_POSIX* file;
mode_t openMode = 0;
SST_OS_DebugAssert(path != NULL, "File path may not be NULL");
/* Async I/O is not yet suppported */
if(mode & SST_OPEN_ASYNC)
return NULL;
/* Only one of SST_OPEN_HINTRAND or SST_OPEN_HINTSEQ may be set. */
if((mode & (SST_OPEN_HINTRAND|SST_OPEN_HINTSEQ)) == (SST_OPEN_HINTRAND|SST_OPEN_HINTSEQ))
return NULL;
switch(mode & 0xF) /* Lower byte has the open mode, remaining 24 bits are flags */
{
/* In each of the three cases (r/w/a), we set the execute bit so that memory mapped
I/O can specify 'execute' a permission too -- apparently the mapped view must be a
subset of the permissions the file was originally opened with. */
case SST_OPEN_READ:
flags = O_RDONLY;
break;
case SST_OPEN_WRITE:
flags = O_WRONLY | O_CREAT | O_TRUNC;
openMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; /* User/Group: RW, Other: R */
break;
case SST_OPEN_APPEND:
flags = O_WRONLY | O_APPEND;
break;
/* Invalid open mode */
default:
return NULL;
}
fd = open(path, flags, openMode);
if(fd < 0)
return NULL;
#if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L
if(mode & SST_OPEN_HINTRAND)
posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM);
else if(mode & SST_OPEN_HINTSEQ)
posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
#endif
file = (SST_File_POSIX*)malloc(sizeof(SST_File_POSIX));
if(file == NULL)
{
close(fd);
return NULL;
}
file->fd = fd;
file->isAsync = (int)(mode & SST_OPEN_ASYNC); /* Not yet used */
#ifdef _DEBUG
file->nrMmaps = 0;
#endif
return (SST_File)file;
}
/******************************************************************************/
uint64_t SST_OS_WriteFile(SST_File file, const void* buf, uint64_t bytes)
{
SST_File_POSIX* fp = (SST_File_POSIX*)file;
uint64_t bytesLeft = bytes;
uint64_t totalWritten;
const char* writePtr = (const char*)buf;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
SST_OS_DebugAssert(buf != NULL, "Buffer may not be NULL");
SST_OS_DebugAssert(!fp->isAsync, "Files opened for asynchronous I/O may not use the synchronous file I/O functions");
#ifdef _DEBUG
SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!");
#endif
/* Do nothing? */
if(bytes == 0)
return 0;
totalWritten = 0;
do
{
size_t nrBytesToWrite;
ssize_t nrWritten;
/* Determine how many bytes to write */
if(bytesLeft > SIZE_MAX)
nrBytesToWrite = SIZE_MAX;
else
nrBytesToWrite = (size_t)bytesLeft;
/* Actually write data to the file */
nrWritten = write(fp->fd, writePtr, nrBytesToWrite);
if(nrWritten < 0) /* error */
{
/* OK, but some of the data may have been written, so stop now but return how far we did get */
break;
}
/* Advance pointers and counters */
writePtr += nrWritten;
totalWritten += (uint64_t)nrWritten;
bytesLeft -= (uint64_t)nrWritten;
} while(bytesLeft > 0);
return totalWritten;
}
/******************************************************************************/
uint64_t SST_OS_ReadFile(SST_File file, void* buf, uint64_t bytes)
{
SST_File_POSIX* fp = (SST_File_POSIX*)file;
uint64_t bytesLeft = bytes;
uint64_t totalRead;
char* readPtr = (char*)buf;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
SST_OS_DebugAssert(buf != NULL, "Buffer may not be NULL");
SST_OS_DebugAssert(!fp->isAsync, "Files opened for asynchronous I/O may not use the synchronous file I/O functions");
#ifdef _DEBUG
SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!");
#endif
/* Do nothing? */
if(bytes == 0)
return 0;
totalRead = 0;
do
{
size_t nrBytesToRead;
ssize_t nrRead;
/* Determine how many bytes to read */
if(bytesLeft > SIZE_MAX)
nrBytesToRead = SIZE_MAX;
else
nrBytesToRead = (size_t)bytesLeft;
nrRead = read(fp->fd, readPtr, nrBytesToRead);
if(nrRead <= 0)
{
/* Error or EOF, but some of the reads could have succeeded, so return how much
was read */
break;
}
/* Advance pointers and counters */
readPtr += nrRead;
totalRead += (uint64_t)nrRead;
bytesLeft -= (uint64_t)nrRead;
} while(bytesLeft > 0);
return totalRead;
}
/******************************************************************************/
int SST_OS_GetFilePointer(SST_File file, uint64_t* fpReturn)
{
SST_File_POSIX* fp = (SST_File_POSIX*)file;
off_t off;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
SST_OS_DebugAssert(fpReturn != NULL, "File pointer return may not be NULL");
#ifdef _DEBUG
SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!");
#endif
off = lseek(fp->fd, 0, SEEK_CUR);
if(off == (off_t)-1)
return 0;
*fpReturn = (uint64_t)off;
return 1;
}
/******************************************************************************/
int SST_OS_SetFilePointer(SST_File file, uint64_t ptr)
{
SST_File_POSIX* fp = (SST_File_POSIX*)file;
off_t off;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
#ifdef _DEBUG
SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!");
#endif
/* Trying to seek > 4GB but underlying OS doesn't support it -> error */
if(sizeof(off_t) == sizeof(uint32_t) && ptr > UINT32_MAX)
return 0;
off = (off_t)ptr;
if(lseek(fp->fd, off, SEEK_SET) != (off_t)-1)
return 0;
return 1;
}
/******************************************************************************/
int SST_OS_FileEOF(SST_File file)
{
SST_File_POSIX* fp = (SST_File_POSIX*)file;
off_t here, eof;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
#ifdef _DEBUG
SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!");
#endif
/* Step 1: Get current file position */
here = lseek(fp->fd, 0, SEEK_CUR);
if(here == (off_t)-1)
return -1;
/* Step 2: Seek to EOF */
eof = lseek(fp->fd, 0, SEEK_END);
if(eof == (off_t)-1)
return -2;
/* Step 3: Put it back! */
lseek(fp->fd, here, SEEK_SET);
/* Step 4: Compare and return */
return (here == eof);
}
/******************************************************************************/
void SST_OS_FlushFile(SST_File file)
{
SST_File_POSIX* fp = (SST_File_POSIX*)file;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
(void)fsync(fp->fd);
}
/******************************************************************************/
void SST_OS_CloseFile(SST_File file)
{
SST_File_POSIX* fp = (SST_File_POSIX*)file;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
if(fp->fd > 0)
{
close(fp->fd);
#ifdef _DEBUG
fp->fd = 0;
#endif
}
#ifdef _DEBUG
SST_OS_DebugAssert(fp->nrMmaps == 0, "Closing file with open memory maps means leaked OS resources");
#endif
free(fp);
}
/******************************************************************************/
int SST_OS_SeekFile(SST_File file, int64_t offset, int fromWhere)
{
SST_File_POSIX* fp = (SST_File_POSIX*)file;
int method;
off_t off;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
#ifdef _DEBUG
SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!");
#endif
off = (off_t)offset;
/* Map SST to POSIX constants (pretty sure they are isomorphic) */
switch(fromWhere)
{
case SST_SEEK_START: method = SEEK_SET; break;
case SST_SEEK_CUR: method = SEEK_CUR; break;
case SST_SEEK_END: method = SEEK_END; break;
/* Invalid parameter */
default: return 0;
}
if(lseek(fp->fd, off, method) == (off_t)-1)
return 0;
return 1;
}
/******************************************************************************/
uint64_t SST_OS_GetFileSize(SST_File file)
{
SST_File_POSIX* fp = (SST_File_POSIX*)file;
struct stat info;
if(fstat(fp->fd, &info) == 0) /* i.e. success */
return (uint64_t)info.st_size;
/* Failure */
return UINT64_MAX;
}
/******************************************************************************/

370
libsst-os/SST_File_Win32.c Normal file
View File

@@ -0,0 +1,370 @@
/*
SST_File_Win32.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os file I/O for Win32 platforms (Windows 7 or later)
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include "Win32Private.h"
#include <SST/SST_File.h>
#include <SST/SST_Assert.h>
/*************************************************************************/
SST_File SST_OS_OpenFile(const char* path, uint32_t mode)
{
DWORD accessFlags;
DWORD createFlags;
DWORD otherFlags;
DWORD shareFlags;
HANDLE hFile;
SST_File_Win32* file;
SST_OS_DebugAssert(path != NULL, "File path may not be NULL");
/* Async I/O is not yet suppported */
/* see win32 flag FILE_FLAG_OVERLAPPED */
if(mode & SST_OPEN_ASYNC)
return NULL;
/* Only one of SST_OPEN_HINTRAND or SST_OPEN_HINTSEQ may be set. */
if((mode & (SST_OPEN_HINTRAND|SST_OPEN_HINTSEQ)) == (SST_OPEN_HINTRAND|SST_OPEN_HINTSEQ))
return NULL;
otherFlags = FILE_ATTRIBUTE_NORMAL;
switch(mode & 0xF) /* Lower byte has the open mode, remaining 24 bits are flags */
{
/* In each of the three cases (r/w/a), we set the execute bit so that memory mapped
I/O can specify 'execute' a permission too -- apparently the mapped view must be a
subset of the permissions the file was originally opened with. */
case SST_OPEN_READ:
createFlags = OPEN_EXISTING;
accessFlags = GENERIC_READ | GENERIC_EXECUTE;
shareFlags = FILE_SHARE_READ;
break;
case SST_OPEN_WRITE:
createFlags = CREATE_ALWAYS;
accessFlags = GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE;
shareFlags = 0;
break;
case SST_OPEN_APPEND:
createFlags = OPEN_ALWAYS;
accessFlags = FILE_APPEND_DATA;
shareFlags = 0;
break;
/* Invalid open mode */
default:
return NULL;
}
if(mode & SST_OPEN_HINTRAND)
otherFlags |= FILE_FLAG_RANDOM_ACCESS;
else if(mode & SST_OPEN_HINTSEQ)
otherFlags |= FILE_FLAG_SEQUENTIAL_SCAN;
hFile = CreateFileA(path, accessFlags, shareFlags, NULL, createFlags, otherFlags, NULL);
if(hFile == INVALID_HANDLE_VALUE)
return NULL;
/* Append mode: start at end of file */
if((mode & 0xF) == SST_OPEN_APPEND)
SetFilePointer(hFile, 0, NULL, FILE_END);
/* Can't use malloc(), so use the process heap */
file = (SST_File_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_File_Win32));
if(file == NULL)
{
CloseHandle(hFile);
return NULL;
}
file->hFile = hFile;
file->hMap = NULL;
file->isAsync = (int)(mode & SST_OPEN_ASYNC); /* Not yet used */
file->accessFlags = accessFlags;
#ifdef _DEBUG
file->nrMmaps = 0;
#endif
return (SST_File)file;
}
/*************************************************************************/
uint64_t SST_OS_WriteFile(SST_File file, const void* buf, uint64_t bytes)
{
SST_File_Win32* fp = (SST_File_Win32*)file;
uint64_t bytesLeft = bytes;
uint64_t totalWritten;
const char* writePtr = (const char*)buf;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
SST_OS_DebugAssert(buf != NULL, "Buffer may not be NULL");
SST_OS_DebugAssert(!fp->isAsync, "Files opened for asynchronous I/O may not use the synchronous file I/O functions");
#ifdef _DEBUG
SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!");
#endif
/* Do nothing? */
if(bytes == 0)
return 0;
totalWritten = 0;
do
{
DWORD nrBytesToWrite, nrWritten;
/* Determine how many bytes to write (at most 4GB per WriteFile() call) */
if(bytesLeft > (uint64_t)0xFFFFFFFF)
nrBytesToWrite = 0xFFFFFFFF;
else
nrBytesToWrite = (DWORD)bytesLeft;
/* Ensure invalid 'nrWritten' before calling WriteFile() */
nrWritten = 0;
/* Actually write data to the file */
if(WriteFile(fp->hFile, writePtr, nrBytesToWrite, &nrWritten, NULL) == FALSE)
{
/* OK, but some of the data may have been written, so stop now but return how far we did get */
break;
}
/* Advance pointers and counters */
writePtr += nrWritten;
totalWritten += (uint64_t)nrWritten;
bytesLeft -= (uint64_t)nrWritten;
} while(bytesLeft > 0);
return totalWritten;
}
/*************************************************************************/
uint64_t SST_OS_ReadFile(SST_File file, void* buf, uint64_t bytes)
{
SST_File_Win32* fp = (SST_File_Win32*)file;
uint64_t bytesLeft = bytes;
uint64_t totalRead;
char* readPtr = (char*)buf;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
SST_OS_DebugAssert(buf != NULL, "Buffer may not be NULL");
SST_OS_DebugAssert(!fp->isAsync, "Files opened for asynchronous I/O may not use the synchronous file I/O functions");
#ifdef _DEBUG
SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!");
#endif
/* Do nothing? */
if(bytes == 0)
return 0;
totalRead = 0;
do
{
DWORD nrBytesToRead, nrRead;
/* Determine how many bytes to read (at most 4GB per ReadFile() call) */
if(bytesLeft > (uint64_t)0xFFFFFFFF)
nrBytesToRead = 0xFFFFFFFF;
else
nrBytesToRead = (DWORD)bytesLeft;
/* Ensure invalid 'nrRead' before calling ReadFile() */
nrRead = 0;
if(ReadFile(fp->hFile, readPtr, nrBytesToRead, &nrRead, NULL) == FALSE)
{
/* Error, but some of the reads could have succeeded, so return how much
was read */
break;
}
/* When nrRead is 0 but ReadFile() returns true, then the EOF is hit */
if(nrRead == 0)
break;
/* Advance pointers and counters */
readPtr += (size_t)nrRead;
totalRead += (uint64_t)nrRead;
bytesLeft -= (uint64_t)nrRead;
} while(bytesLeft > 0);
return totalRead;
}
/*************************************************************************/
int SST_OS_GetFilePointer(SST_File file, uint64_t* fpReturn)
{
SST_File_Win32* fp = (SST_File_Win32*)file;
LARGE_INTEGER zeroPos, newPos;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
SST_OS_DebugAssert(fpReturn != NULL, "File pointer return may not be NULL");
#ifdef _DEBUG
SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!");
#endif
/* Zero bytes from 'current' = just get the position */
zeroPos.QuadPart = 0;
if(SetFilePointerEx(fp->hFile, zeroPos, &newPos, FILE_CURRENT) == FALSE)
return 0;
*fpReturn = (uint64_t)newPos.QuadPart;
return 1;
}
/*************************************************************************/
int SST_OS_SetFilePointer(SST_File file, uint64_t ptr)
{
SST_File_Win32* fp = (SST_File_Win32*)file;
LARGE_INTEGER pos;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
#ifdef _DEBUG
SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!");
#endif
/* Set it */
pos.QuadPart = (LONGLONG)ptr;
if(SetFilePointerEx(fp->hFile, pos, NULL, FILE_BEGIN) == FALSE)
return 0;
return 1;
}
/*************************************************************************/
int SST_OS_FileEOF(SST_File file)
{
SST_File_Win32* fp = (SST_File_Win32*)file;
LARGE_INTEGER ptr, end, zero;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
#ifdef _DEBUG
SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!");
#endif
zero.QuadPart = 0;
/* Step 1: Get current file position */
if(SetFilePointerEx(fp->hFile, zero, &ptr, FILE_CURRENT) == FALSE)
return -2;
/* Step 2: Get end of file position */
if(GetFileSizeEx(fp->hFile, &end) == FALSE)
return -3;
/* Step 3: Compare */
return (ptr.QuadPart == end.QuadPart);
}
/*************************************************************************/
void SST_OS_FlushFile(SST_File file)
{
SST_File_Win32* fp = (SST_File_Win32*)file;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
(void)FlushFileBuffers(fp->hFile);
}
/*************************************************************************/
void SST_OS_CloseFile(SST_File file)
{
SST_File_Win32* fp = (SST_File_Win32*)file;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
if(fp->hFile != NULL)
{
CloseHandle(fp->hFile);
#ifdef _DEBUG
fp->hFile = NULL;
#endif
}
if(fp->hMap != NULL)
{
CloseHandle(fp->hMap);
#ifdef _DEBUG
fp->hMap = NULL;
#endif
}
#ifdef _DEBUG
SST_OS_DebugAssert(fp->nrMmaps == 0, "Closing file with open memory maps means leaked OS resources");
#endif
HeapFree(GetProcessHeap(), 0, fp);
}
/*************************************************************************/
int SST_OS_SeekFile(SST_File file, int64_t offset, int fromWhere)
{
SST_File_Win32* fp = (SST_File_Win32*)file;
LARGE_INTEGER pos;
DWORD method;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
#ifdef _DEBUG
SST_OS_DebugAssert(fp->nrMmaps == 0, "Cannot use synchronous file I/O while memory maps exist!");
#endif
/* Map SST to Win32 constants (pretty sure they are isomorphic) */
switch(fromWhere)
{
case SST_SEEK_START: method = FILE_BEGIN; break;
case SST_SEEK_CUR: method = FILE_CURRENT; break;
case SST_SEEK_END: method = FILE_END; break;
/* Invalid parameter */
default: return 0;
}
/* Save the offset, then do it */
pos.QuadPart = (LONGLONG)offset;
if(SetFilePointerEx(fp->hFile, pos, NULL, method) == FALSE)
return 0;
return 1;
}
/*************************************************************************/
uint64_t SST_OS_GetFileSize(SST_File file)
{
SST_File_Win32* fp = (SST_File_Win32*)file;
LARGE_INTEGER size;
if(GetFileSizeEx(fp->hFile, &size))
return (uint64_t)size.QuadPart;
/* Failure */
return UINT64_MAX;
}
/*************************************************************************/

170
libsst-os/SST_Mmap_POSIX.c Normal file
View File

@@ -0,0 +1,170 @@
/*
SST_Mmap_POSIX.c
Author: Patrick Baggett <ptb1@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os memory mapped file I/O functions for POSIX
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include "POSIXPrivate.h"
#include <sys/stat.h>
#include <SST/SST_Mmap.h>
#include <SST/SST_SysMem.h> /* SST_PROTECT_XXXXX constants, SST_OS_GetPageSize() */
#include <SST/SST_Assert.h>
void __libsst_init_mmapsize() { /* Not used on POSIX */ }
/******************************************************************************/
uint32_t SST_OS_GetMmapGranularity(void)
{
return SST_OS_GetPageSize();
}
/******************************************************************************/
SST_MemoryMap SST_OS_CreateMmap(SST_File file, uint64_t offset, size_t mapLength, int mode)
{
SST_File_POSIX* fp = (SST_File_POSIX*)file;
SST_MemoryMap_POSIX* mm;
int access = 0;
void* ptr;
off_t off;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
SST_OS_DebugAssert((mode & (~(SST_PROTECT_READ|SST_PROTECT_WRITE|SST_PROTECT_EXEC))) == 0, "The mode bits may only contain SST_PROTECT_READ/WRITE/EXEC and nothing else");
SST_OS_DebugAssert((offset & (SST_OS_GetMmapGranularity()-1)) == 0, "Offset must be aligned to system granularity. Use SST_OS_GetMmapGranuality() to determine this");
SST_OS_DebugAssert( (offset == 0 && mapLength == 0) || mapLength > 0, "Map length must be non-zero OR offset and length must both be zero (map whole file)");
if(mode & SST_PROTECT_READ)
access |= PROT_READ;;
if(mode & SST_PROTECT_WRITE)
access |= PROT_WRITE;
if(mode & SST_PROTECT_EXEC)
access |= PROT_EXEC;
off = (off_t)offset;
/* Map whole file */
if(mapLength == 0)
{
struct stat s;
if(fstat(fp->fd, &s) == 0)
mapLength = (size_t)s.st_size;
else /* fstat() failed, try lseek() */
{
off_t here, end;
here = lseek(fp->fd, 0, SEEK_CUR);
end = lseek(fp->fd, 0, SEEK_END);
/* failed? */
if(here == (off_t)-1 || end == (off_t)-1)
return NULL;
mapLength = (size_t)end;
/* Restore file position (not that it matters much if you mmap() the whole thing) */
lseek(fp->fd, here, SEEK_SET);
}
}
ptr = mmap(NULL, mapLength, access, MAP_SHARED, fp->fd, off);
if(ptr == MAP_FAILED)
return NULL;
/* Allocate a memory map region */
mm = (SST_MemoryMap_POSIX*)malloc(sizeof(SST_MemoryMap_POSIX));
if(mm == NULL)
{
munmap(ptr, mapLength);
return NULL;
}
mm->offset = offset;
mm->len = mapLength;
mm->base = ptr;
#ifdef _DEBUG
mm->owner = fp;
fp->nrMmaps++;
#endif
return (SST_MemoryMap)mm;
}
/******************************************************************************/
void SST_OS_DestroyMmap(SST_MemoryMap mappedRegion)
{
SST_MemoryMap_POSIX* mm = (SST_MemoryMap_POSIX*)mappedRegion;
SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL");
munmap(mm->base, mm->len);
#ifdef _DEBUG
mm->base = NULL;
mm->owner->nrMmaps--;
#endif
free(mm);
}
/******************************************************************************/
void* SST_OS_GetMmapBase(SST_MemoryMap mappedRegion)
{
SST_MemoryMap_POSIX* mm = (SST_MemoryMap_POSIX*)mappedRegion;
SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL");
return mm->base;
}
/******************************************************************************/
size_t SST_OS_GetMmapSize(SST_MemoryMap mappedRegion)
{
SST_MemoryMap_POSIX* mm = (SST_MemoryMap_POSIX*)mappedRegion;
SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL");
return mm->len;
}
/******************************************************************************/
uint64_t SST_OS_GetMmapOffset(SST_MemoryMap mappedRegion)
{
SST_MemoryMap_POSIX* mm = (SST_MemoryMap_POSIX*)mappedRegion;
SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL");
return mm->offset;
}
/******************************************************************************/
void SST_OS_SyncMmap(SST_MemoryMap mappedRegion)
{
SST_MemoryMap_POSIX* mm = (SST_MemoryMap_POSIX*)mappedRegion;
SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL");
/* Synchronize with the OS, but do so async */
msync(mm->base, mm->len, MS_ASYNC);
}

188
libsst-os/SST_Mmap_Win32.c Normal file
View File

@@ -0,0 +1,188 @@
/*
SST_Mmap_Win32.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os memory mapped file I/O functions for Win32 systems (Windows 7 or later)
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include "Win32Private.h"
#include <SST/SST_Mmap.h>
#include <SST/SST_SysMem.h> /* SST_PROTECT_XXXXX constants */
#include <SST/SST_Assert.h>
#if !defined(FILE_MAP_EXECUTE) /* Added in Windows XP SP2 */
#define FILE_MAP_EXECUTE 0x20
#endif
static uint32_t allocGranularity;
void __libsst_init_mmapsize()
{
SYSTEM_INFO si;
GetNativeSystemInfo(&si);
allocGranularity = (uint32_t)si.dwAllocationGranularity;
}
/*************************************************************************/
uint32_t SST_OS_GetMmapGranularity(void)
{
return allocGranularity;
}
/*************************************************************************/
SST_MemoryMap SST_OS_CreateMmap(SST_File file, uint64_t offset, size_t mapLength, int mode)
{
SST_File_Win32* fp = (SST_File_Win32*)file;
SST_MemoryMap_Win32* mm;
DWORD access, offsetLow, offsetHigh;
void* ptr;
SST_OS_DebugAssert(file != NULL, "File handle may not be NULL");
SST_OS_DebugAssert((mode & (~(SST_PROTECT_READ|SST_PROTECT_WRITE|SST_PROTECT_EXEC))) == 0, "The mode bits may only contain SST_PROTECT_READ/WRITE/EXEC and nothing else");
SST_OS_DebugAssert((offset & (SST_OS_GetMmapGranularity()-1)) == 0, "Offset must be aligned to system granularity. Use SST_OS_GetMmapGranuality() to determine this");
SST_OS_DebugAssert((offset == 0 && mapLength == 0) || mapLength > 0, "Map length must be non-zero OR offset and length must both be zero (map whole file)");
/* No file mapping yet? */
if(fp->hMap == NULL)
{
DWORD pageProt;
/* Decide on protection flags. See SST_File_Win32.c/SST_OS_OpenFile() for the 'case' values */
switch(fp->accessFlags)
{
case GENERIC_READ | GENERIC_EXECUTE: pageProt = PAGE_EXECUTE_READ; break;
case GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE: pageProt = PAGE_EXECUTE_READWRITE; break;
default: return NULL;
}
/* Actually create the file mapping */
fp->hMap = CreateFileMappingA(fp->hFile, NULL, pageProt, 0, 0, NULL);
if(fp->hMap == NULL)
return NULL;
}
/* Windows is weird about its flags: it allows {R, W} + {X}, so only 4 combinations of
possible values. However, the 'W' bit implies 'R'. */
if(mode & SST_PROTECT_READ)
access = FILE_MAP_READ;
if(mode & SST_PROTECT_WRITE)
access = FILE_MAP_WRITE; /* This is actually r/w, which is why we don't use "else if(...)" */
if(mode & SST_PROTECT_EXEC)
access |= FILE_MAP_EXECUTE;
offsetLow = (DWORD)(offset & 0xFFFFFFFF);
offsetHigh = (DWORD)(offset >> 32);
/* Windows already treats a mapLength == 0 as "map to end of file". We just ensure (at the top) that
offset == 0 so it really means "map from beginning to end". */
ptr = MapViewOfFileEx(fp->hMap, access, offsetHigh, offsetLow, mapLength, NULL);
if(ptr == NULL)
return NULL;
/* Allocate a memory map region */
mm = (SST_MemoryMap_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_MemoryMap_Win32));
if(mm == NULL)
{
UnmapViewOfFile(ptr);
return NULL;
}
if(mapLength == 0)
{
LARGE_INTEGER size;
GetFileSizeEx(fp->hFile, &size);
mapLength = (size_t)size.QuadPart;
}
mm->offset = offset;
mm->len = mapLength;
mm->base = ptr;
#ifdef _DEBUG
mm->owner = fp;
fp->nrMmaps++;
#endif
return (SST_MemoryMap)mm;
}
/*************************************************************************/
void SST_OS_DestroyMmap(SST_MemoryMap mappedRegion)
{
SST_MemoryMap_Win32* mm = (SST_MemoryMap_Win32*)mappedRegion;
SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL");
UnmapViewOfFile(mm->base);
#ifdef _DEBUG
mm->base = NULL;
mm->owner->nrMmaps--;
#endif
HeapFree(GetProcessHeap(), 0, mm);
}
/*************************************************************************/
void* SST_OS_GetMmapBase(SST_MemoryMap mappedRegion)
{
SST_MemoryMap_Win32* mm = (SST_MemoryMap_Win32*)mappedRegion;
SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL");
return mm->base;
}
/*************************************************************************/
size_t SST_OS_GetMmapSize(SST_MemoryMap mappedRegion)
{
SST_MemoryMap_Win32* mm = (SST_MemoryMap_Win32*)mappedRegion;
SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL");
return mm->len;
}
/*************************************************************************/
uint64_t SST_OS_GetMmapOffset(SST_MemoryMap mappedRegion)
{
SST_MemoryMap_Win32* mm = (SST_MemoryMap_Win32*)mappedRegion;
SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL");
return mm->offset;
}
/*************************************************************************/
void SST_OS_SyncMmap(SST_MemoryMap mappedRegion)
{
SST_MemoryMap_Win32* mm = (SST_MemoryMap_Win32*)mappedRegion;
SST_OS_DebugAssert(mappedRegion != NULL, "Memory map handle may not be NULL");
FlushViewOfFile(mm->base, mm->len);
}

33
libsst-os/SST_OSInit.c Normal file
View File

@@ -0,0 +1,33 @@
/*
SST_OSInit.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 5/29/2013
Purpose:
libsst-os initialization function
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
extern void __libsst_init_endian();
extern void __libsst_init_pagesize();
extern void __libsst_init_mmapsize();
extern int __libsst_init_time();
extern int __libsst_init_user();
int SST_OS_Init()
{
__libsst_init_endian();
__libsst_init_pagesize();
__libsst_init_mmapsize();
return __libsst_init_time() && __libsst_init_user();
}

View File

@@ -0,0 +1,407 @@
/*
SST_SafeArithmetic.c
Author: Chris Ertel <crertel@762studios.com>
Created: 1/16/2012
Purpose:
Functions to help perform integer arithmetic while catching overflow conditions.
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include <SST/SST_SafeArithmetic.h>
#include <limits.h>
int SST_OS_SafeAddI8(int8_t _a, int8_t _b, int8_t* _out)
{
int8_t ret = _a + _b;
/* if they are opposite signs, they cannot overflow */
if ( (_a >= 0 && _b <= 0) ||
(_b >= 0 && _a <= 0) )
{
*_out = ret;
return 1;
}
/* if they are the same sign, check for overflow */
if (_a < 0 || _b < 0)
{
if (ret > _a && ret > _b)
return 0;
}
else
{
if (ret < _a && ret < _b)
return 0;
}
*_out = ret;
return 1;
}
int SST_OS_SafeAddI8ToSizeT(int8_t _a, size_t _size, size_t* _out)
{
size_t ret = _size + _a;
if (_a >= 0)
{
if (ret < _size)
return 0;
}
else
{
if (ret > _size)
return 0;
}
*_out = ret;
return 1;
}
int SST_OS_SafeAddU8(uint8_t _a, uint8_t _b, uint8_t* _out)
{
uint8_t ret = _a + _b;
if (ret < _a || ret < _b)
return 0;
*_out = ret;
return 1;
}
int SST_OS_SafeMultiplyU8(uint8_t _a, uint8_t _b, uint8_t* _out)
{
uint16_t a = _a;
uint16_t b = _b;
uint16_t ret = a*b;
if (ret > 0xff)
return 0;
*_out = (uint8_t) ret;
return 1;
}
int SST_OS_SafeAddU8ToSizeT(uint8_t _a, size_t _size, size_t* _out)
{
size_t ret = _a + _size;
if (ret < _size)
return 0;
*_out = ret;
return 1;
}
int SST_OS_SafeAddI16(int16_t _a, int16_t _b, int16_t* _out)
{
int16_t ret = _a + _b;
/* if they are opposite signs, they cannot overflow */
if ( (_a >= 0 && _b <= 0) ||
(_b >= 0 && _a <= 0) )
{
*_out = ret;
return 1;
}
/* if they are the same sign, check for overflow */
if (_a < 0 || _b < 0)
{
if (ret > _a && ret > _b)
return 0;
}
else
{
if (ret < _a && ret < _b)
return 0;
}
*_out = ret;
return 1;
}
int SST_OS_SafeAddI16ToSizeT(int16_t _a, size_t _size, size_t* _out)
{
size_t ret = _size + _a;
if (_a >= 0)
{
if (ret < _size)
return 0;
}
else
{
if (ret > _size)
return 0;
}
*_out = ret;
return 1;
}
int SST_OS_SafeAddU16(uint16_t _a, uint16_t _b, uint16_t* _out)
{
uint16_t ret = _a + _b;
if (ret < _a || ret < _b)
return 0;
*_out = ret;
return 1;
}
int SST_OS_SafeMultiplyU16(uint16_t _a, uint16_t _b, uint16_t* _out)
{
uint32_t a = _a;
uint32_t b = _b;
uint32_t ret = a*b;
if (ret > 0xffff)
return 0;
*_out = (uint16_t) ret;
return 1;
}
int SST_OS_SafeAddU16ToSizeT(uint16_t _a, size_t _size, size_t* _out)
{
size_t ret = _a + _size;
if (ret < _size)
return 0;
*_out = ret;
return 1;
}
int SST_OS_SafeAddI32(int32_t _a, int32_t _b, int32_t* _out)
{
int32_t ret = _a + _b;
/* if they are opposite signs, they cannot overflow */
if ( (_a >= 0 && _b <= 0) ||
(_b >= 0 && _a <= 0) )
{
*_out = ret;
return 1;
}
/* if they are the same sign, check for overflow */
if (_a < 0 || _b < 0)
{
if (ret > _a && ret > _b)
return 0;
}
else
{
if (ret < _a && ret < _b)
return 0;
}
*_out = ret;
return 1;
}
int SST_OS_SafeAddI32ToSizeT(int32_t _a, size_t _size, size_t* _out)
{
size_t ret = _size + _a;
if (_a >= 0)
{
if (ret < _size)
return 0;
}
else
{
if (ret > _size)
return 0;
}
*_out = ret;
return 1;
}
int SST_OS_SafeAddU32(uint32_t _a, uint32_t _b, uint32_t* _out)
{
uint32_t ret = _a + _b;
if (ret < _b || ret < _a)
return 0;
*_out = ret;
return 1;
}
int SST_OS_SafeMultiplyU32(uint32_t _a, uint32_t _b, uint32_t* _out)
{
uint64_t a = _a;
uint64_t b = _b;
uint64_t ret = a*b;
if (ret > 0xffffffff)
return 0;
*_out = (uint32_t) ret;
return 1;
}
int SST_OS_SafeAddU32ToSizeT(uint32_t _a, size_t _size, size_t* _out)
{
size_t ret = _a + _size;
if (ret < _size)
return 0;
*_out = ret;
return 1;
}
int SST_OS_SafeAddI64(int64_t _a, int64_t _b, int64_t* _out)
{
int64_t ret = _a + _b;
/* if they are opposite signs, they cannot overflow */
if ( (_a >= 0 && _b <= 0) ||
(_b >= 0 && _a <= 0) )
{
*_out = ret;
return 1;
}
/* if they are the same sign, check for overflow */
if (_a < 0 || _b < 0)
{
if (ret > _a && ret > _b)
return 0;
}
else
{
if (ret < _a && ret < _b)
return 0;
}
*_out = ret;
return 1;
}
int SST_OS_SafeAddI64ToSizeT(int64_t _a, size_t _size, size_t* _out)
{
/* Positive value being added */
if(_a >= 0)
{
/*
Some weirdness with the casting: if you cast 32-bit size_t to
a signed int64_t, it can sign extend the value. This is bad.
We want to zero extend to 64 bits, *then* interpret that as
a 64-bit integer. In other words, size_t -> int64_t should
always be a positive integer, and the upper 32-bits are zero.
On 64-bit machines where size_t is 64 bits, then the cast
will never do a sign extend.
*/
const int64_t diff64 = (int64_t)((uint64_t)(SIZE_MAX - _size));
/* Then it shouldn't matter */
if(_a > diff64)
return 0;
}
else /* Negative value being added. */
{
const int64_t size64 = (int64_t)((uint64_t)_size);
/* Ensure that if _a was added, the results
would be > 0, otherwise it is negative we
would overflow */
if(size64 + _a < 0)
{
return 0;
}
}
*_out = (size_t)_a + _size;
return 1;
}
int SST_OS_SafeAddU64(uint64_t _a, uint64_t _b, uint64_t* _out)
{
uint64_t ret = _a + _b;
if (ret < _a || ret < _b)
return 0;
*_out = ret;
return 1;
}
/* SLOWSLOW This is obviously correct, but not fast. Use LUTs or something. */
static int countHighestSetBitU64(uint64_t _in)
{
int ret = 0;
while (_in > 0)
{
_in >>= 1;
ret++;
}
return ret;
}
/* NOTE: For explanation, see ( http://stackoverflow.com/a/199455 ). */
int SST_OS_SafeMultiplyU64(uint64_t _a, uint64_t _b, uint64_t* _out)
{
uint64_t ret;
int log2a;
int log2b;
/* special-case for 1 -- probably not needed */
if (_a == 1 || _b == 1)
{
*_out = _a*_b;
return 1;
}
log2a = countHighestSetBitU64(_a);
log2b = countHighestSetBitU64(_b);
if (log2a + log2b > 64)
return 0;
ret = _a*_b;
*_out = ret;
return 1;
}
int SST_OS_SafeAddU64ToSizeT(uint64_t _a, size_t _size, size_t* _out)
{
const size_t diff = SIZE_MAX - _size;
const uint64_t diff64 = (uint64_t)diff;
if(diff64 < _a)
return 0;
*_out = (size_t)_a + _size;
return 1;
}
int SST_OS_SafeAddSizeTToSizeT( size_t _a, size_t _b, size_t* _out)
{
size_t out = _a + _b;
if (out < _a && out < _b)
return 0;
*_out = out;
return 1;
}

View File

@@ -0,0 +1,147 @@
/*
SST_SysMem_POSIX.c
Author: Patrick Baggett <ptb1@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os system memory allocation functions for POSIX platforms
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include "POSIXPrivate.h"
#include <SST/SST_SysMem.h>
#include <SST/SST_Assert.h>
#ifdef __APPLE__
#include<sys/sysctl.h>
#endif
static uint32_t cached_pagesize;
void __libsst_init_pagesize()
{
uint32_t pgsz = (uint32_t)-1;
#ifdef _SC_PAGESIZE
pgsz = (uint32_t)sysconf(_SC_PAGESIZE);
#elif defined(_SC_PAGE_SIZE)
if(pgsz == (uint32_t)-1)
pgsz = (uint32_t)sysconf(_SC_PAGE_SIZE);
#endif
cached_pagesize = pgsz;
}
/******************************************************************************/
uint64_t SST_OS_GetMemorySize()
{
#ifdef __APPLE__
int param[2] = { CTL_HW, HW_MEMSIZE };
uint64_t mem;
size_t size = sizeof(mem);
sysctl(param, 2, &mem, &size, NULL, 0);
return mem;
#else
uint32_t pagesize = SST_OS_GetPageSize();
uint32_t pages;
pages = sysconf(_SC_PHYS_PAGES);
if(pages == (uint32_t)-1)
return 0;
return (uint64_t)pages*(uint64_t)pagesize;
#endif
}
/******************************************************************************/
uint32_t SST_OS_GetPageSize()
{
return cached_pagesize;
}
/******************************************************************************/
void* SST_OS_AllocPages(size_t allocBytes)
{
void* addr;
#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
int flags = MAP_SHARED | MAP_ANON;
#else
int flags = MAP_SHARED | MAP_ANONYMOUS;
#endif
SST_OS_DebugAssert(allocBytes > 0, "Allocating 0 bytes is not allowed");
#ifdef MAP_UNINITIALIZED /* Linux only, 2.6.33+, don't zero pages */
flags |= MAP_UNINITIALIZED;
#endif
addr = mmap(NULL, allocBytes, PROT_READ | PROT_WRITE, flags, -1, 0);
if(addr == MAP_FAILED)
return NULL;
return addr;
}
/******************************************************************************/
int SST_OS_FreePages(void* pageBase, size_t nrBytes)
{
uintptr_t addr;
uint32_t pageSize;
SST_OS_DebugAssert(pageBase != NULL, "Base address may not be NULL");
SST_OS_DebugAssert(nrBytes > 0, "The number of bytes to free may not be zero");
addr = (uintptr_t)pageBase;
pageSize = SST_OS_GetPageSize();
/* Check if address is aligned to page boundary */
if(addr & (pageSize-1))
return -1;
/* Free the pages */
return (munmap(pageBase, nrBytes) == 0);
}
/******************************************************************************/
int SST_OS_ProtectPages(void* pageBase, size_t nrBytes, int protectFlags)
{
uintptr_t addr;
uint32_t pageSize;
int newFlags = 0;
SST_OS_DebugAssert(pageBase != NULL, "Base address may not be NULL");
SST_OS_DebugAssert(nrBytes > 0, "The number of bytes to free may not be zero");
SST_OS_DebugAssert((protectFlags & (~(SST_PROTECT_READ|SST_PROTECT_WRITE|SST_PROTECT_EXEC))) == 0, "Protect flags contain invalid bits");
addr = (uintptr_t)pageBase;
pageSize = SST_OS_GetPageSize();
/* Check if address is aligned to page boundary */
if(addr & (pageSize-1))
return -1;
if(protectFlags & SST_PROTECT_READ)
newFlags |= PROT_READ;
if(protectFlags & SST_PROTECT_WRITE)
newFlags |= PROT_WRITE;
if(protectFlags & SST_PROTECT_EXEC)
newFlags |= PROT_EXEC;
return (mprotect(pageBase, nrBytes, newFlags) == 0);
}

View File

@@ -0,0 +1,155 @@
/*
SST_SysMem_Win32.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os system memory allocation functions for Win32 platforms (Windows 7 or later)
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include "Win32Private.h"
#include <SST/SST_SysMem.h>
#include <SST/SST_Assert.h>
static uint32_t cached_pagesize;
void __libsst_init_pagesize()
{
SYSTEM_INFO info;
GetNativeSystemInfo(&info);
cached_pagesize = (uint32_t)info.dwPageSize;
}
/* Round an allocation of 'amount' bytes to be a multiple of 'pageSize' */
static size_t roundToPage(uint32_t pageSize, size_t amount)
{
size_t rounded;
/* ASSUMPTION: pageSize is a power of two */
/*
Algorithm: Round up allocation to the nearest page.
[1] x & (pageSize-1) = Bytes that are extra parts of a page
[2] x & (~(pageSize-1)) = Bytes that are whole pages.
Start with [2] bytes. If [1] is non-zero, then add page size.
*/
rounded = amount & (~(pageSize-1));
if(amount & (pageSize-1))
rounded += pageSize;
return rounded;
}
/*************************************************************************/
uint64_t SST_OS_GetMemorySize()
{
ULONGLONG mem = 0;
if(GetPhysicallyInstalledSystemMemory(&mem))
return (uint64_t)mem;
return 0;
}
/*************************************************************************/
uint32_t SST_OS_GetPageSize()
{
return cached_pagesize;
}
/*************************************************************************/
void* SST_OS_AllocPages(size_t allocBytes)
{
SST_OS_DebugAssert(allocBytes > 0, "Allocating 0 bytes is not allowed");
return VirtualAllocEx(GetCurrentProcess(), NULL, roundToPage(SST_OS_GetPageSize(), allocBytes), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
}
/*************************************************************************/
int SST_OS_FreePages(void* pageBase, size_t nrBytes)
{
uintptr_t addr;
uint32_t pageSize;
SST_OS_DebugAssert(pageBase != NULL, "Base address may not be NULL");
SST_OS_DebugAssert(nrBytes > 0, "The number of bytes to free may not be zero");
addr = (uintptr_t)pageBase;
pageSize = SST_OS_GetPageSize();
/* Check if address is aligned to page boundary */
if(addr & (pageSize-1))
return -1;
/* Free the pages */
if(VirtualFreeEx(GetCurrentProcess(), pageBase, roundToPage(pageSize, nrBytes), MEM_DECOMMIT | MEM_RELEASE) != 0)
return 1;
return 0;
}
/*************************************************************************/
int SST_OS_ProtectPages(void* pageBase, size_t nrBytes, int protectFlags)
{
uintptr_t addr;
uint32_t pageSize;
DWORD newFlags = PAGE_NOACCESS;
SST_OS_DebugAssert(pageBase != NULL, "Base address may not be NULL");
SST_OS_DebugAssert(nrBytes > 0, "The number of bytes to free may not be zero");
addr = (uintptr_t)pageBase;
pageSize = SST_OS_GetPageSize();
/* Check if address is aligned to page boundary */
if(addr & (pageSize-1))
return -1;
/* Microsoft doesn't believe in bitfields. This switch brought to you by a poor design decision */
switch(protectFlags)
{
/* r/o */
case SST_PROTECT_READ: newFlags = PAGE_READONLY; break;
/* r/w, w/o */
case SST_PROTECT_READ | SST_PROTECT_WRITE:
case SST_PROTECT_WRITE: newFlags = PAGE_READWRITE; break; /* Win32 doesn't have w/o */
/* x/o */
case SST_PROTECT_EXEC: newFlags = PAGE_EXECUTE; break;
/* w/x */
case SST_PROTECT_WRITE | SST_PROTECT_EXEC: newFlags = PAGE_EXECUTE_READWRITE; break;
/* r/x */
case SST_PROTECT_READ | SST_PROTECT_EXEC: newFlags = PAGE_EXECUTE_READ; break;
/* r/w/x */
case SST_PROTECT_READ | SST_PROTECT_WRITE | SST_PROTECT_EXEC: newFlags = PAGE_EXECUTE_READWRITE; break;
}
if(VirtualProtectEx(GetCurrentProcess(), (void*)addr, roundToPage(pageSize, nrBytes), newFlags, NULL) != 0)
return 1;
return 0;
}

View File

@@ -0,0 +1,60 @@
/*
SST_Time_MacOSX.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 5/30/2013
Purpose:
libsst-os timing functions for MacOSX systems
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include <SST/SST_Time.h>
#include <mach/mach_time.h>
/******************************************************************************/
static mach_timebase_info_data_t info;
/******************************************************************************/
int __libsst_init_time()
{
return (mach_timebase_info(&info) == KERN_SUCCESS);
}
/******************************************************************************/
static uint64_t absToNsec(uint64_t abstime)
{
return abstime * info.numer / info.denom;
}
/******************************************************************************/
uint64_t SST_OS_GetMicroTime()
{
return absToNsec(mach_absolute_time()) / 1000;
}
/******************************************************************************/
uint64_t SST_OS_GetMilliTime()
{
return absToNsec(mach_absolute_time()) / 1000000;
}
/******************************************************************************/
double SST_OS_GetFloatingTime()
{
return absToNsec(mach_absolute_time()) / 1000000000.0;
}

View File

@@ -0,0 +1,85 @@
/*
SST_Time_POSIX.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 5/29/2013
Purpose:
libsst-os timing functions for POSIX systems
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/*
Sadly, MacOS X does not implement clock_gettime(), so it has its own file
*/
#include <SST/SST_Time.h>
#include <time.h>
struct timespec freq;
static clockid_t timeSource =
#if defined(CLOCK_MONOTONIC_RAW) /* Linux >= 2.6.28 */
CLOCK_MONOTONIC_RAW;
#else
CLOCK_MONOTONIC;
#endif
int __libsst_init_time()
{
struct timespec v;
int clkOk = (clock_gettime(timeSource, &v) > 0);
if(!clkOk)
{
#if defined(CLOCK_MONOTONIC_RAW)
timeSource = CLOCK_MONOTONIC;
clkOk = (clock_gettime(timeSource, &v) > 0);
if(!clkOk)
#else
timeSource = CLOCK_REALTIME;
#endif
if(clock_gettime(timeSource, &v) < 0)
return 0;
}
return 1;
}
uint64_t SST_OS_GetMicroTime()
{
struct timespec v;
clock_gettime(timeSource, &v);
return (uint64_t)((v.tv_sec * 1000000) + (v.tv_nsec / 1000));
}
uint64_t SST_OS_GetMilliTime() /* Not be confused with Miller Time (TM) :D */
{
struct timespec v;
clock_gettime(timeSource, &v);
return (uint64_t)((v.tv_sec * 1000) + (v.tv_nsec / 1000000));
}
double SST_OS_GetFloatingTime()
{
struct timespec v;
clock_gettime(timeSource, &v);
return (double)v.tv_sec + (v.tv_nsec / 1000000000.0);
}

View File

@@ -0,0 +1,80 @@
/*
SST_Time_Win32.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 5/29/2013
Purpose:
libsst-os timing functions for Win32
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include <SST/SST_Time.h>
#include <windows.h>
static LARGE_INTEGER freq; /* Frequency, as 64-bit integer */
static double dfreq; /* Frequency, as a double value */
/*
Quick note about frequencies:
x86 PCs typically have various sources of timers, but these 3 are the most common:
* RDTSC -- x86 instruction to read a cycle counter, varies per CPU but can be in the low GHz range.
* ACPI -- Advanced Configuration and Power Interface timer, about 3.57 MHz (so, about 280 nanosecond accuracy)
* i8254 -- Intel chip on keyboard, about 1.193 MHz (so, about 838 nanosecond accuracy)
*/
int __libsst_init_time()
{
BOOL ok = QueryPerformanceFrequency(&freq);
if(ok)
dfreq = (double)freq.QuadPart;
return (int)ok;
}
uint64_t SST_OS_GetRawTime()
{
LARGE_INTEGER v;
QueryPerformanceCounter(&v);
return (uint64_t)v.QuadPart;
}
uint64_t SST_OS_GetRawFrequency()
{
return (uint64_t)freq.QuadPart;
}
uint64_t SST_OS_GetMicroTime()
{
LARGE_INTEGER v;
QueryPerformanceCounter(&v);
return (uint64_t)((v.QuadPart * 1000LL * 1000LL) / freq.QuadPart);
}
uint64_t SST_OS_GetMilliTime() /* Not be confused with Miller Time (TM) :D */
{
LARGE_INTEGER v;
QueryPerformanceCounter(&v);
return (uint64_t)((v.QuadPart * 1000LL) / freq.QuadPart);
}
double SST_OS_GetFloatingTime()
{
LARGE_INTEGER v;
QueryPerformanceCounter(&v);
return (double)v.QuadPart / dfreq;
}

152
libsst-os/SST_User_POSIX.c Normal file
View File

@@ -0,0 +1,152 @@
/*
SST_User_POSIX.c
Author: Patrick Baggett <ptb1@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os user account information functions for POSIX platforms
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <string.h>
int __libsst_init_user() { return 1; }
/******************************************************************************/
int SST_OS_GetUserName(char* usernameReturn, int bufferSize)
{
uid_t euid;
struct passwd pwd;
struct passwd* ptrpwd = NULL;
char buf[1024];
int len;
/* Here we using the POSIX '95 extension for reentrant functions */
euid = geteuid();
if(getpwuid_r(euid, &pwd, buf, sizeof(buf), &ptrpwd) != 0)
return -1;
/* getpwuid_r() will return 0 to indicate success, but it does not indicate that a matching
record was found, just that the arguments weren't incorrect. Check if *ptrpwd is still NULL,
which means the record wasn't found. */
if(ptrpwd == NULL)
return 0;
len = (int)strlen(pwd.pw_name);
/* Is the user just querying the length? */
if(usernameReturn == NULL)
return len;
/* Expected case: (more than) enough space -> just do strcpy() */
if(bufferSize >= len+1)
{
strcpy(usernameReturn, pwd.pw_name);
return len;
}
/* Exceptional case: less than enough space. Copy 'bufferSize'-1 characters, then add NULL terminator. */
memcpy(usernameReturn, pwd.pw_name, bufferSize-1);
usernameReturn[bufferSize-1] = 0;
return len;
}
/******************************************************************************/
int SST_OS_GetUserRealName(char* realnameReturn, int bufferSize)
{
uid_t euid;
struct passwd pwd;
struct passwd* ptrpwd = NULL;
char buf[1024];
int len;
/* Here we using the POSIX '95 extension for reentrant functions */
euid = geteuid();
if(getpwuid_r(euid, &pwd, buf, sizeof(buf), &ptrpwd) != 0)
return -1;
/* getpwuid_r() will return 0 to indicate success, but it does not indicate that a matching
record was found, just that the arguments weren't incorrect. Check if *ptrpwd is still NULL,
which means the record wasn't found. */
if(ptrpwd == NULL)
return 0;
len = (int)strlen(pwd.pw_gecos);
/* Is the user just querying the length? */
if(realnameReturn == NULL)
return len;
/* Expected case: (more than) enough space -> just do strcpy() */
if(bufferSize >= len+1)
{
strcpy(realnameReturn, pwd.pw_gecos);
return len;
}
/* Exceptional case: less than enough space. Copy 'bufferSize'-1 characters, then add NULL terminator. */
memcpy(realnameReturn, pwd.pw_gecos, bufferSize-1);
realnameReturn[bufferSize-1] = 0;
return len;
}
/******************************************************************************/
int SST_OS_GetUserHomeDirectory(char* homedirReturn, int bufferSize)
{
uid_t euid;
struct passwd pwd;
struct passwd* ptrpwd = NULL;
char buf[1024];
int len;
/* Here we using the POSIX '95 extension for reentrant functions */
euid = geteuid();
if(getpwuid_r(euid, &pwd, buf, sizeof(buf), &ptrpwd) != 0)
return -1;
/* getpwuid_r() will return 0 to indicate success, but it does not indicate that a matching
record was found, just that the arguments weren't incorrect. Check if *ptrpwd is still NULL,
which means the record wasn't found. */
if(ptrpwd == NULL)
return 0;
len = (int)strlen(pwd.pw_dir);
/* Is the user just querying the length? */
if(homedirReturn == NULL)
return len;
/* Expected case: (more than) enough space -> just do strcpy() */
if(bufferSize >= len+1)
{
strcpy(homedirReturn, pwd.pw_dir);
return len;
}
/* Exceptional case: less than enough space. Copy 'bufferSize'-1 characters, then add NULL terminator. */
memcpy(homedirReturn, pwd.pw_dir, bufferSize-1);
homedirReturn[bufferSize-1] = 0;
return len;
}

197
libsst-os/SST_User_Win32.c Normal file
View File

@@ -0,0 +1,197 @@
/*
SST_User_Win32.c
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 12/23/2011
Purpose:
libsst-os user information functions for Win32 systems (Windows 7 or later)
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#define _CRT_SECURE_NO_WARNINGS /* strncpy() isn't deprecated, stupid programming is */
#include "Win32Private.h"
#include <userenv.h>
#include <SST/SST_User.h>
#include <malloc.h> //_alloca() on Win32
static HMODULE advapi32_dll = NULL;
static BOOL (WINAPI * pfOpenProcessToken)(_In_ HANDLE ProcessHandle, _In_ DWORD DesiredAccess, _Out_ PHANDLE TokenHandle) = NULL;
static BOOL (WINAPI * pfGetUserNameA)(_Out_ LPSTR lpBuffer, _Inout_ LPDWORD lpnSize) = NULL;
static HMODULE userenv_dll = NULL;
static BOOL (WINAPI * pfGetUserProfileDirectoryA)(_In_ HANDLE hToken,_Out_opt_ LPSTR lpProfileDir, _Inout_ LPDWORD lpcchSize) = NULL;
void libsst_free_user()
{
pfOpenProcessToken = NULL;
pfGetUserNameA = NULL;
pfGetUserProfileDirectoryA = NULL;
if(advapi32_dll)
{
FreeLibrary(advapi32_dll);
advapi32_dll = NULL;
}
if(userenv_dll)
{
FreeLibrary(userenv_dll);
userenv_dll = NULL;
}
}
int __libsst_init_user()
{
advapi32_dll = LoadLibraryA("advapi32.dll");
if(advapi32_dll == NULL)
return 0;
userenv_dll = LoadLibraryA("userenv.dll");
if(userenv_dll == NULL)
{
FreeLibrary(advapi32_dll);
return 0;
}
/* Load all symbols */
/* advapi32.dll */
pfOpenProcessToken = (BOOL (WINAPI*)(HANDLE,DWORD,PHANDLE))GetProcAddress(advapi32_dll, "OpenProcessToken");
pfGetUserNameA = (BOOL (WINAPI*)(LPSTR, LPDWORD))GetProcAddress(advapi32_dll, "GetUserNameA");
/* userenv.dll */
pfGetUserProfileDirectoryA = (BOOL (WINAPI*)(HANDLE, LPSTR,LPDWORD))GetProcAddress(userenv_dll, "GetUserProfileDirectoryA");
/* Verify all loaded */
if(pfOpenProcessToken == NULL || pfGetUserNameA == NULL || pfGetUserProfileDirectoryA == NULL)
{
libsst_free_user();
return 0;
}
return 1;
}
int SST_OS_GetUserName(char* usernameReturn, int bufferSize)
{
DWORD size;
/* User is querying the username size */
if(usernameReturn == NULL)
{
char dummy[1];
/* This *should* generate the insufficient buffer error. When it does, it returns
the correct size in 'size'. */
size = sizeof(dummy);
pfGetUserNameA(dummy, &size);
/* Make sure it really did. */
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
return (int)size-1;
/* Some other error :( */
return -1;
}
size = (DWORD)bufferSize;
if(pfGetUserNameA(usernameReturn, &size) == FALSE)
{
/* GetUserName() returns false on insufficient space, but that is OK.
However, errors for any other reason isn't OK, so catch them here. */
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return -2;
}
return (int)(size-1);
}
int SST_OS_GetUserRealName(char* realnameReturn, int bufferSize)
{
/* TODO: better implementation here plz */
return SST_OS_GetUserName(realnameReturn, bufferSize);
}
int SST_OS_GetUserHomeDirectory(char* homedirReturn, int bufferSize)
{
HANDLE hToken = NULL;
DWORD size;
int retcode;
#ifdef _DEBUG
if(homedirReturn && bufferSize < 0)
return -1;
#endif
if(pfOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) == FALSE)
return -2;
/* User is querying the username size */
if(homedirReturn == NULL)
{
char dummy[1]; /* See comment block */
size = 0;
/*
Bug in GetUserProfileDirectoryA() impl: NULL for 2nd param should be allowed but isn't.
MSDN: "If the buffer specified by lpProfileDir is not large enough or lpProfileDir is NULL, the function fails
and this parameter receives the necessary buffer size, including the terminating null character."
However, in practice, when I set the second param to NULL, `size` remains zero.
*/
pfGetUserProfileDirectoryA(hToken, dummy, &size);
if(size == 0)
retcode = -3;
else
retcode = (int)(size-1);
}
else /* Actually getting the size */
{
/* Set the size to the user provided size and query*/
size = (DWORD)bufferSize;
if(pfGetUserProfileDirectoryA(hToken, homedirReturn, &size) == FALSE)
{
/* This gets tricky: the function doesn't write partial paths, so we have to first detect
if the error was due to buffer size */
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
char* tmpbuf = (char*)_alloca(size);
/* OK, now we've ensured we have a correctly-sized buffer, so call it again. */
if(pfGetUserProfileDirectoryA(hToken, tmpbuf, &size) == FALSE)
{
/* Failed second time around, doh -- give up */
retcode = -4;
}
else
{
/* Success -- copy n-1 characters, then null terminate */
strncpy(homedirReturn, tmpbuf, bufferSize-1);
homedirReturn[bufferSize-1] = 0;
retcode = (int)size-1;
}
}
}
else /* Success */
retcode = (int)(size-1);
}
CloseHandle(hToken);
return retcode;
}

168
libsst-os/Win32Private.h Normal file
View File

@@ -0,0 +1,168 @@
/*
Win32Private.h
Author: Patrick Baggett <ptbaggett@762studios.com>
Created: 12/23/2011
Purpose:
Private data structures for Win32 implementation of libsst-os. Not to be distributed
as part of public SDK headers.
License:
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*/
#pragma once
#ifndef _WIN32PRIVATE_H
#define _WIN32PRIVATE_H
#define _WIN32_WINNT 0x0601 /* Windows 7 or later */
#include <windows.h>
#include <pstdint.h>
#if defined(__GNUC__) /* Missing Windows 7 API on various GCC targets, remove when is fixed. */
typedef ULONG_PTR KAFFINITY;
typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP {
RelationProcessorCore,
RelationNumaNode,
RelationCache,
RelationProcessorPackage,
RelationGroup,
RelationAll = 0xffff
} LOGICAL_PROCESSOR_RELATIONSHIP;
typedef enum _PROCESSOR_CACHE_TYPE {
CacheUnified,
CacheInstruction,
CacheData,
CacheTrace
} PROCESSOR_CACHE_TYPE;
typedef struct _CACHE_DESCRIPTOR {
BYTE Level;
BYTE Associativity;
WORD LineSize;
DWORD Size;
PROCESSOR_CACHE_TYPE Type;
} CACHE_DESCRIPTOR, *PCACHE_DESCRIPTOR;
typedef struct _GROUP_AFFINITY {
KAFFINITY Mask;
WORD Group;
WORD Reserved[3];
} GROUP_AFFINITY, *PGROUP_AFFINITY;
typedef struct _PROCESSOR_NUMBER {
WORD Group;
BYTE Number;
BYTE Reserved;
} PROCESSOR_NUMBER, *PPROCESSOR_NUMBER;
typedef struct _PROCESSOR_GROUP_INFO {
BYTE MaximumProcessorCount;
BYTE ActiveProcessorCount;
BYTE Reserved[38];
KAFFINITY ActiveProcessorMask;
} PROCESSOR_GROUP_INFO, *PPROCESSOR_GROUP_INFO;
typedef struct _PROCESSOR_RELATIONSHIP {
BYTE Flags;
BYTE Reserved[21];
WORD GroupCount;
GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY];
} PROCESSOR_RELATIONSHIP, *PPROCESSOR_RELATIONSHIP;
typedef struct _NUMA_NODE_RELATIONSHIP {
DWORD NodeNumber;
BYTE Reserved[20];
GROUP_AFFINITY GroupMask;
} NUMA_NODE_RELATIONSHIP, *PNUMA_NODE_RELATIONSHIP;
typedef struct _CACHE_RELATIONSHIP {
BYTE Level;
BYTE Associativity;
WORD LineSize;
DWORD CacheSize;
PROCESSOR_CACHE_TYPE Type;
BYTE Reserved[20];
GROUP_AFFINITY GroupMask;
} CACHE_RELATIONSHIP, *PCACHE_RELATIONSHIP;
typedef struct _GROUP_RELATIONSHIP {
WORD MaximumGroupCount;
WORD ActiveGroupCount;
BYTE Reserved[20];
PROCESSOR_GROUP_INFO GroupInfo[ANYSIZE_ARRAY];
} GROUP_RELATIONSHIP, *PGROUP_RELATIONSHIP;
typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION {
ULONG_PTR ProcessorMask;
LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
union {
struct {
BYTE Flags;
} ProcessorCore;
struct {
DWORD NodeNumber;
} NumaNode;
CACHE_DESCRIPTOR Cache;
ULONGLONG Reserved[2];
};
} SYSTEM_LOGICAL_PROCESSOR_INFORMATION, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION;
typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
DWORD Size;
union {
PROCESSOR_RELATIONSHIP Processor;
NUMA_NODE_RELATIONSHIP NumaNode;
CACHE_RELATIONSHIP Cache;
GROUP_RELATIONSHIP Group;
};
} SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
BOOL WINAPI GetLogicalProcessorInformationEx(
LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType,
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer,
PDWORD ReturnedLength);
BOOL WINAPI GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer, PDWORD ReturnLength);
BOOL WINAPI SetThreadIdealProcessorEx(HANDLE hThread, PPROCESSOR_NUMBER lpIdealProcessor, PPROCESSOR_NUMBER lpPreviousIdealProcessor);
#endif
/*************************************************************************/
typedef struct SST_File_Win32
{
HANDLE hFile; /* Handle from CreateFile() */
HANDLE hMap; /* Handle from CreateFileMapping() */
int isAsync; /* Is this file in async mode */
DWORD accessFlags; /* Flags for access used in CreateFileA() */
#ifdef _DEBUG
int nrMmaps; /* Number of outstanding memory maps */
#endif
} SST_File_Win32;
typedef struct SST_MemoryMap_Win32
{
uint64_t offset; /* Offset parameter as given to SST_OS_MmapCreate() */
size_t len; /* Length parameter as given to SST_OS_MmapCreate() */
void* base; /* Returned base address from SST_OS_MmapCreate() */
#ifdef _DEBUG
SST_File_Win32* owner; /* File that created this memory map */
#endif
} SST_MemoryMap_Win32;
#endif

200
libsst-os/libsst-os.vcxproj Normal file
View File

@@ -0,0 +1,200 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{4BAC6D63-C2E8-43F7-87EA-EF953CBFDDD3}</ProjectGuid>
<RootNamespace>libsstos</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v110</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\vsyasm.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)\Lib\x86\</OutDir>
<IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
<TargetName>$(ProjectName)-debug</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)\Lib\x86\</OutDir>
<IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)\Lib\x64\</OutDir>
<IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
<TargetName>$(ProjectName)-debug</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)\Lib\x64\</OutDir>
<IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Lib />
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<PreprocessorDefinitions>SST_ASSERT_NODEBUG=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Lib />
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<PreprocessorDefinitions>SST_ASSERT_NODEBUG=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="SST_Alloc.c" />
<ClCompile Include="SST_Assert.c" />
<ClCompile Include="SST_Assert_Win32.c" />
<ClCompile Include="SST_CPU_Win32.c" />
<ClCompile Include="SST_DynLib_Win32.c" />
<ClCompile Include="SST_Endian.c" />
<ClCompile Include="SST_File_Win32.c" />
<ClCompile Include="SST_FileSys_Win32.c" />
<ClCompile Include="SST_Mmap_Win32.c" />
<ClCompile Include="SST_OSInit.c" />
<ClCompile Include="SST_SafeArithmetic.c" />
<ClCompile Include="SST_SysMem_Win32.c" />
<ClCompile Include="SST_Time_Win32.c" />
<ClCompile Include="SST_User_Win32.c" />
</ItemGroup>
<ItemGroup>
<YASM Include="SST_CPUCache_x86-64-win64.asm">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</YASM>
<YASM Include="SST_CPUCache_x86.asm">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</YASM>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Lib\Include\SST\SST_Time.h" />
<ClInclude Include="Win32Private.h" />
<ClInclude Include="..\Lib\Include\SST\SST_Alloc.h" />
<ClInclude Include="..\Lib\Include\SST\SST_Assert.h" />
<ClInclude Include="..\Lib\Include\SST\SST_Build.h" />
<ClInclude Include="..\Lib\Include\SST\SST_CPU.h" />
<ClInclude Include="..\Lib\Include\SST\SST_CPUCache.h" />
<ClInclude Include="..\Lib\Include\SST\SST_DynLib.h" />
<ClInclude Include="..\Lib\Include\SST\SST_Endian.h" />
<ClInclude Include="..\Lib\Include\SST\SST_File.h" />
<ClInclude Include="..\Lib\Include\SST\SST_FileSys.h" />
<ClInclude Include="..\Lib\Include\SST\SST_Mmap.h" />
<ClInclude Include="..\Lib\Include\SST\SST_OS.h" />
<ClInclude Include="..\Lib\Include\SST\SST_SafeArithmetic.h" />
<ClInclude Include="..\Lib\Include\SST\SST_SysMem.h" />
<ClInclude Include="..\Lib\Include\SST\SST_User.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\libsst-atomic\libsst-atomic.vcxproj">
<Project>{43ed481f-c4a3-40ed-81a3-46c43dc4eb1e}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\vsyasm.targets" />
</ImportGroup>
</Project>

View File

@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="SST_Alloc.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SST_Assert.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SST_Assert_Win32.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SST_CPU_Win32.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SST_DynLib_Win32.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SST_Endian.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SST_File_Win32.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SST_FileSys_Win32.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SST_Mmap_Win32.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SST_SafeArithmetic.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SST_SysMem_Win32.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SST_User_Win32.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SST_Time_Win32.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SST_OSInit.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<YASM Include="SST_CPUCache_x86-64-win64.asm">
<Filter>Source Files</Filter>
</YASM>
<YASM Include="SST_CPUCache_x86.asm">
<Filter>Source Files</Filter>
</YASM>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Win32Private.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_Alloc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_Assert.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_Build.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_CPU.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_CPUCache.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_DynLib.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_Endian.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_File.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_FileSys.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_Mmap.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_OS.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_SafeArithmetic.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_SysMem.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_User.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Lib\Include\SST\SST_Time.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,38 @@
# libsst-os/Source/sources-POSIX.mk
# Author: Patrick Baggett <ptbaggett@762studios.com>
# Created: 12/23/2011
#
# Purpose:
#
# List of source files for POSIX-compliant systems. This reduces the amount
# of copy/pasting for different UNIX configurations.
#
# License:
#
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What The Fuck You Want
# To Public License, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING for more details.
SRC := \
SST_DynLib_POSIX.c \
SST_FileSys_POSIX.c \
SST_File_POSIX.c \
SST_SysMem_POSIX.c \
SST_CPU_POSIX.c \
SST_Mmap_POSIX.c \
SST_User_POSIX.c \
SST_Alloc.c \
SST_Assert.c \
SST_Assert_Generic.c \
SST_Endian.c \
SST_SafeArithmetic.c \
SST_OSInit.c \
# MacOS X doesn't have POSIX realtime extension, so it needs a different implementation. Le sigh.
ifeq ($(OS),Darwin)
SRC += SST_Time_MacOSX.c
else
SRC += SST_Time_POSIX.c
endif

View File

@@ -0,0 +1,18 @@
# libsst-os/sources-Solaris.mk
# Author: Patrick Baggett <ptbaggett@762studios.com>
# Created: 6/21/2012
#
# Purpose:
#
# List of source files for Solaris
#
# License:
#
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What The Fuck You Want
# To Public License, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING for more details.
include sources-POSIX.mk

View File

@@ -0,0 +1,28 @@
# libsst-os/sources-Win32.mk
# Author: Patrick Baggett <ptbaggett@762studios.com>
# Created: 11/09/2012
#
# Purpose:
#
# List of source files for Win32 systems.
#
# License:
#
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What The Fuck You Want
# To Public License, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING for more details.
SRC := \
SST_DynLib_Win32.c \
SST_FileSys_Win32.c \
SST_File_Win32.c \
SST_SysMem_Win32.c \
SST_CPU_Win32.c \
SST_Mmap_Win32.c \
SST_Assert_Win32.c \
SST_Alloc.c \
SST_Assert.c \
SST_Endian.c \
SST_SafeArithmetic.c