Code cleanup and fixes #19

Merged
Mergul merged 5 commits from Demos into master 2021-03-03 18:07:22 +01:00
6 changed files with 174 additions and 144 deletions

View file

@ -40,7 +40,7 @@ test_dmd_betterC:
stage: test stage: test
image: frolvlad/alpine-glibc image: frolvlad/alpine-glibc
script: script:
- binaries/dmd_release_unittest_bc - binaries/dmd_debug_unittest_bc
artifacts: artifacts:
reports: reports:
junit: test_report.xml junit: test_report.xml

View file

@ -19,8 +19,7 @@
"libs-linux-x86_64": ["cimgui","SDL2","SDL2_image"], "libs-linux-x86_64": ["cimgui","SDL2","SDL2_image"],
"lflags-linux-x86_64": ["-rpath=libs/linux/x64/","-Llibs/linux/x64/"], "lflags-linux-x86_64": ["-rpath=libs/linux/x64/","-Llibs/linux/x64/"],
"dflags-ldc" : [ "dflags-ldc" : [
"--ffast-math", "--ffast-math"
"-enable-cross-module-inlining"
], ],
"configurations" : [ "configurations" : [
{ {

View file

@ -1,22 +1,14 @@
module mmutils.thread_pool; module mmutils.thread_pool;
import bubel.ecs.atomic;
//import core.stdc.stdio;
//import core.stdc.stdlib : free, malloc, realloc;
//import core.stdc.string : memcpy;
//import std.stdio;
import std.algorithm : map; import std.algorithm : map;
version = MM_NO_LOGS; // Disable log creation version = MM_NO_LOGS; // Disable log creation
//version = MM_USE_POSIX_THREADS; // Use posix threads insted of standard library, required for betterC //version = MM_USE_POSIX_THREADS; // Use posix threads insted of standard library, required for betterC
version (Posix)version = MM_USE_POSIX_THREADS;
version (WebAssembly) version (WebAssembly)
{ {
version = MM_NO_LOGS; version = MM_NO_LOGS;
version = MM_USE_POSIX_THREADS;
extern(C) struct FILE extern(C) struct FILE
{ {
@ -33,8 +25,15 @@ else
version (D_BetterC) version (D_BetterC)
{ {
import bubel.ecs.std; version (Posix) version = MM_USE_POSIX_THREADS;
extern (C) __gshared int _d_eh_personality(int, int, size_t, void*, void*)
extern (C) void free(void*) @nogc nothrow @system;
extern (C) void* malloc(size_t size) @nogc nothrow @system;
extern (C) void* realloc(void*, size_t size) @nogc nothrow @system;
extern (C) void* memcpy(return void*, scope const void*, size_t size) @nogc nothrow @system;
//hacks for LDC
/*extern (C) __gshared int _d_eh_personality(int, int, size_t, void*, void*)
{ {
return 0; return 0;
} }
@ -47,7 +46,7 @@ version (D_BetterC)
extern (C) void* _d_allocmemory(size_t sz) extern (C) void* _d_allocmemory(size_t sz)
{ {
return malloc(sz); return malloc(sz);
} }*/
} }
else else
{ {
@ -56,8 +55,132 @@ else
} }
////////////////////////////////////////////// //////////////////////////////////////////////
//////////////////// Alloc /////////////////// /////////////// Atomics //////////////////////
////////////////////////////////////////////// //////////////////////////////////////////////
version (ECSEmscripten)
{
import std.traits;
enum MemoryOrder
{
acq,
acq_rel,
raw,
rel,
seq
}
extern (C) ubyte emscripten_atomic_cas_u8(void* addr, ubyte oldVal, ubyte newVal) @nogc nothrow pure;
extern (C) ushort emscripten_atomic_cas_u16(void* addr, ushort oldVal, ushort newVal) @nogc nothrow pure;
extern (C) uint emscripten_atomic_cas_u32(void* addr, uint oldVal, uint newVal) @nogc nothrow pure;
extern (C) ubyte emscripten_atomic_load_u8(const void* addr) @nogc nothrow pure;
extern (C) ushort emscripten_atomic_load_u16(const void* addr) @nogc nothrow pure;
extern (C) uint emscripten_atomic_load_u32(const void* addr) @nogc nothrow pure;
extern (C) ubyte emscripten_atomic_store_u8(void* addr, ubyte val) @nogc nothrow pure;
extern (C) ushort emscripten_atomic_store_u16(void* addr, ushort val) @nogc nothrow pure;
extern (C) uint emscripten_atomic_store_u32(void* addr, uint val) @nogc nothrow pure;
extern (C) ubyte emscripten_atomic_add_u8(void* addr, ubyte val) @nogc nothrow pure;
extern (C) ushort emscripten_atomic_add_u16(void* addr, ushort val) @nogc nothrow pure;
extern (C) uint emscripten_atomic_add_u32(void* addr, uint val) @nogc nothrow pure;
extern (C) ubyte emscripten_atomic_sub_u8(void* addr, ubyte val) @nogc nothrow pure;
extern (C) ushort emscripten_atomic_sub_u16(void* addr, ushort val) @nogc nothrow pure;
extern (C) uint emscripten_atomic_sub_u32(void* addr, uint val) @nogc nothrow pure;
public pure nothrow @nogc Unqual!T atomicOp(string op, T, V1)(ref shared T val, V1 mod)
{
static if (op == "+=")
{
static if (is(T == byte) || is(T == ubyte))
return cast(Unqual!T)(emscripten_atomic_add_u8(cast(void*)&val,
cast(Unqual!T) mod) + 1);
else static if (is(T == short) || is(T == ushort))
return cast(Unqual!T)(emscripten_atomic_add_u16(cast(void*)&val,
cast(Unqual!T) mod) + 1);
else static if (is(T == int) || is(T == uint))
return cast(Unqual!T)(emscripten_atomic_add_u32(cast(void*)&val,
cast(Unqual!T) mod) + 1);
else
static assert(0);
}
else static if (op == "-=")
{
static if (is(T == byte) || is(T == ubyte))
return cast(Unqual!T)(emscripten_atomic_sub_u8(cast(void*)&val,
cast(Unqual!T) mod) - 1);
else static if (is(T == short) || is(T == ushort))
return cast(Unqual!T)(emscripten_atomic_sub_u16(cast(void*)&val,
cast(Unqual!T) mod) - 1);
else static if (is(T == int) || is(T == uint))
return cast(Unqual!T)(emscripten_atomic_sub_u32(cast(void*)&val,
cast(Unqual!T) mod) - 1);
else
static assert(0);
}
}
public pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val,
V newval)
{
alias UT = Unqual!T;
static if (is(UT == bool) || is(UT == byte) || is(UT == ubyte))
emscripten_atomic_store_u8(cast(void*)&val, cast(UT) newval);
else static if (is(UT == short) || is(UT == ushort))
emscripten_atomic_store_u16(cast(void*)&val, cast(UT) newval);
else static if (is(UT == int) || is(UT == uint))
emscripten_atomic_store_u32(cast(void*)&val, cast(UT) newval);
else
static assert(0);
}
public pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(
ref const T val)
{
alias UT = Unqual!T;
static if (is(UT == bool))
return emscripten_atomic_load_u8(cast(const void*)&val) != 0;
else static if (is(UT == byte) || is(UT == ubyte))
return emscripten_atomic_load_u8(cast(const void*)&val);
else static if (is(UT == short) || is(UT == ushort))
return emscripten_atomic_load_u16(cast(const void*)&val);
else static if (is(UT == int) || is(UT == uint))
return emscripten_atomic_load_u32(cast(const void*)&val);
else
static assert(0);
}
public pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq,
MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis)
{
alias UT = Unqual!T;
static if (is(UT == bool))
return emscripten_atomic_cas_u8(cast(void*) here,
cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis;
else static if (is(UT == byte) || is(UT == ubyte))
return emscripten_atomic_cas_u8(cast(void*) here,
cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis;
else static if (is(UT == short) || is(UT == ushort))
return emscripten_atomic_cas_u16(cast(void*) here,
cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis;
else static if (is(UT == int) || is(UT == uint))
return emscripten_atomic_cas_u32(cast(void*) here,
cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis;
else
static assert(0);
}
}
else
{
public import core.atomic;
}
//////////////////////////////////////////////////
//////////////////// Allocator ///////////////////
//////////////////////////////////////////////////
T* makeVar(T)(T init) T* makeVar(T)(T init)
{ {
T* el = cast(T*) malloc(T.sizeof); T* el = cast(T*) malloc(T.sizeof);
@ -120,21 +243,7 @@ long useconds()
{ {
version (WebAssembly) version (WebAssembly)
{ {
//import core.sys.posix.sys.time : gettimeofday, timeval;
/*timeval t;
gettimeofday(&t, null);
return t.tv_sec * 1_000_000 + t.tv_usec;*/
//time_t time;
//timespec spec;
//lock_gettime(CLOCK_REALTIME, &spec);
return cast(long)(emscripten_get_now() * 1000.0); return cast(long)(emscripten_get_now() * 1000.0);
//time = spec.tv_sec;
//return spec.tv_sec * 1000_000 + spec.tv_nsec / 1000;
} }
else version (Posix) else version (Posix)
{ {
@ -146,6 +255,7 @@ long useconds()
} }
else version (Windows) else version (Windows)
{ {
//TODO: implement timer on windows
/*import core.sys.windows.windows : QueryPerformanceFrequency; /*import core.sys.windows.windows : QueryPerformanceFrequency;
__gshared double mul = -1; __gshared double mul = -1;
@ -243,7 +353,7 @@ version (MM_USE_POSIX_THREADS)
version (WebAssembly) version (WebAssembly)
{ {
extern(C): extern(C):
//alias uint time_t;
struct pthread_attr_t struct pthread_attr_t
{ {
union union
@ -259,19 +369,11 @@ version (MM_USE_POSIX_THREADS)
uint x; uint x;
} }
/*struct timespec
{
time_t tv_sec;
int tv_nsec;
}*/
// pthread // pthread
int pthread_create(pthread_t*, in pthread_attr_t*, void* function(void*), void*); int pthread_create(pthread_t*, in pthread_attr_t*, void* function(void*), void*);
int pthread_join(pthread_t, void**); int pthread_join(pthread_t, void**);
void pthread_exit(void *retval); void pthread_exit(void *retval);
// semaphore.h
//alias sem_t = void*;
struct sem_t struct sem_t
{ {
shared int[4] __val; shared int[4] __val;
@ -282,8 +384,6 @@ version (MM_USE_POSIX_THREADS)
int sem_post(sem_t*); int sem_post(sem_t*);
int sem_destroy(sem_t*); int sem_destroy(sem_t*);
int sem_timedwait(sem_t* sem, const timespec* abstime); int sem_timedwait(sem_t* sem, const timespec* abstime);
//import core.sys.posix.pthread;
//import core.sys.posix.semaphore;
} }
else version (Posix) else version (Posix)
{ {
@ -347,7 +447,6 @@ version (MM_USE_POSIX_THREADS)
bool tryWait() bool tryWait()
{ {
//return true;
int ret = sem_trywait(&mutex); int ret = sem_trywait(&mutex);
return (ret == 0); return (ret == 0);
} }
@ -411,91 +510,7 @@ version (MM_USE_POSIX_THREADS)
} }
else version(D_BetterC) else version(D_BetterC)
{ {
version(Posix) version(Windows)
{
import core.sys.posix.pthread;
import core.sys.posix.semaphore;
struct Semaphore
{
sem_t mutex;
void initialize()
{
sem_init(&mutex, 0, 0);
}
void wait()
{
int ret = sem_wait(&mutex);
assert(ret == 0);
}
bool tryWait()
{
//return true;
int ret = sem_trywait(&mutex);
return (ret == 0);
}
bool timedWait(int usecs)
{
timespec tv;
// if there is no such a function look at it: https://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows
clock_gettime(CLOCK_REALTIME, &tv);
tv.tv_sec += usecs / 1_000_000;
tv.tv_nsec += (usecs % 1_000_000) * 1_000;
int ret = sem_timedwait(&mutex, &tv);
return (ret == 0);
}
void post()
{
int ret = sem_post(&mutex);
assert(ret == 0);
}
void destroy()
{
sem_destroy(&mutex);
}
}
private extern (C) void* threadRunFunc(void* threadVoid)
{
Thread* th = cast(Thread*) threadVoid;
th.threadStart();
pthread_exit(null);
return null;
}
struct Thread
{
alias DG = void delegate();
DG threadStart;
pthread_t handle;
void start(DG dg)
{
threadStart = dg;
int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this);
if(!ok)handle = pthread_t();
//assert(ok == 0);
}
void join()
{
pthread_join(handle, null);
handle = handle.init;
threadStart = null;
}
}
}
else version(Windows)
{ {
import core.stdc.stdint : uintptr_t; import core.stdc.stdint : uintptr_t;
import core.sys.windows.windows; import core.sys.windows.windows;
@ -551,15 +566,13 @@ else version(D_BetterC)
case WAIT_TIMEOUT: case WAIT_TIMEOUT:
return false; return false;
default: default:
assert(0);//throw new SyncError( "Unable to wait for semaphore" ); assert(0, "Unable to wait for semaphore" );
} }
} }
void post() void post()
{ {
assert(ReleaseSemaphore( handle, 1, null )); assert(ReleaseSemaphore( handle, 1, null ));
//if ( !ReleaseSemaphore( m_hndl, 1, null ) )
//throw new SyncError( "Unable to notify semaphore" );
} }
void destroy() void destroy()
@ -575,7 +588,6 @@ else version(D_BetterC)
th.threadStart(); th.threadStart();
//(null);
ExitThread(0); ExitThread(0);
return 0; return 0;
} }
@ -591,21 +603,22 @@ else version(D_BetterC)
{ {
threadStart = dg; threadStart = dg;
handle = cast(HANDLE) _beginthreadex( null, 0, &threadRunFunc, cast(void*)&this, 0, null ); handle = cast(HANDLE) _beginthreadex( null, 0, &threadRunFunc, cast(void*)&this, 0, null );
//int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this);
//assert(handle != null);
} }
void join() void join()
{ {
if ( WaitForSingleObject( handle, INFINITE ) == WAIT_OBJECT_0 )assert(0); if ( WaitForSingleObject( handle, INFINITE ) == WAIT_OBJECT_0 )assert(0);
CloseHandle( handle ); CloseHandle( handle );
//pthread_join(handle, null);
handle = handle.init; handle = handle.init;
threadStart = null; threadStart = null;
} }
} }
} }
else
{
static assert(0, "Platform is unsupported in betterC mode!");
}
} }
else else
{ {
@ -674,7 +687,7 @@ else
///////////////// ThreadPool ///////////////// ///////////////// ThreadPool /////////////////
////////////////////////////////////////////// //////////////////////////////////////////////
private enum gMaxThreadsNum = 32; private enum gMaxThreadsNum = 64;
alias JobDelegate = void delegate(ThreadData*, JobData*); alias JobDelegate = void delegate(ThreadData*, JobData*);

View file

@ -18,6 +18,27 @@ else
} }
} }
version(Android)
{
alias pthread_key_t = uint;
extern (C) int pthread_key_create(pthread_key_t *, void* function(void *)) @nogc nothrow;
extern (C) int pthread_key_delete(pthread_key_t) @nogc nothrow;
extern (C) void* pthread_getspecific(pthread_key_t) @nogc nothrow;
extern (C) int pthread_setspecific(pthread_key_t, const void *) @nogc nothrow;
}
else version(WebAssembly)
{
alias pthread_key_t = uint;
extern (C) int pthread_key_create(pthread_key_t *, void* function(void *)) @nogc nothrow;
extern (C) int pthread_key_delete(pthread_key_t) @nogc nothrow;
extern (C) void* pthread_getspecific(pthread_key_t) @nogc nothrow;
extern (C) int pthread_setspecific(pthread_key_t, const void *) @nogc nothrow;
extern (C) void emscripten_main_thread_process_queued_calls();
}
struct ECSJobUpdater struct ECSJobUpdater
{ {

View file

@ -29,7 +29,7 @@
"subConfigurations": "subConfigurations":
{ {
"bindbc-sdl": "static", "bindbc-sdl": "static",
"ecs":"library" "bubel_ecs":"library"
} }
}, },
{ {
@ -41,7 +41,7 @@
"subConfigurations": "subConfigurations":
{ {
"bindbc-sdl": "staticBC", "bindbc-sdl": "staticBC",
"ecs":"library-betterC" "bubel_ecs":"library-betterC"
} }
} }
] ]

View file

@ -50,8 +50,7 @@
], ],
"dflags": [ "dflags": [
"-unittest" "-unittest"
], ]
"targetName" : "ecs"
}, },
{ {
"name": "unittest-runner-cov", "name": "unittest-runner-cov",
@ -65,8 +64,7 @@
"dflags": [ "dflags": [
"-unittest", "-unittest",
"-cov" "-cov"
], ]
"targetName" : "ecs"
}, },
{ {
"name" : "library-betterC", "name" : "library-betterC",
@ -129,8 +127,7 @@
"excludedSourceFiles":[ "excludedSourceFiles":[
"source\/win_dll.d", "source\/win_dll.d",
"tests/tests.d" "tests/tests.d"
], ]
"targetName" : "ecs"
} }
] ]
} }