Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/torch/threads-ffi.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRonan Collobert <ronan@collobert.com>2015-04-14 08:09:28 +0300
committerRonan Collobert <ronan@collobert.com>2015-04-21 04:54:18 +0300
commit9665a4b99eed85ccfad1e03a581ff14428d6dace (patch)
tree23f2f0e068c3817227abb046456f2110b8d2b606 /lib
parentd223e9d60ed04f91016867065a5ef7575d337dce (diff)
moved away from FFI
- removed the ffi dependency... now runs under lua! - support for low-level thread - support for basic mutex and condition variables from lua - better error messaging - better reliability - more doc - no more addjobasync() - no sdl
Diffstat (limited to 'lib')
-rw-r--r--lib/THThread.c241
-rw-r--r--lib/THThread.h26
-rw-r--r--lib/init.c10
-rw-r--r--lib/luaTHRD.h84
-rw-r--r--lib/queue.c383
-rw-r--r--lib/threads.c263
6 files changed, 1007 insertions, 0 deletions
diff --git a/lib/THThread.c b/lib/THThread.c
new file mode 100644
index 0000000..4e503fb
--- /dev/null
+++ b/lib/THThread.c
@@ -0,0 +1,241 @@
+#ifndef TH_THREAD_INC
+#define TH_THREAD_INC
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "TH.h"
+#include "THThread.h"
+
+#if defined(USE_PTHREAD_THREADS)
+#include <pthread.h>
+
+#elif defined(USE_WIN32_THREADS)
+
+/* very basic emulation to suit our needs */
+
+#include <process.h>
+#include <windows.h>
+
+typedef HANDLE pthread_t;
+typedef DWORD pthread_attr_t;
+typedef HANDLE pthread_mutex_t;
+typedef HANDLE pthread_cond_t;
+
+static int pthread_create(pthread_t *restrict thread,
+ const pthread_attr_t *restrict attr, void *(*start_routine)(void *),
+ void *restrict arg)
+{
+ *thread = (HANDLE)_beginthreadex(NULL, 0, (THREAD_FUNCTION)start_routine, arg, 0, NULL);
+ return (int)(*thread == NULL);
+}
+
+static int pthread_join(pthread_t thread, void **value_ptr)
+{
+ return ((WaitForSingleObject((thread), INFINITE) != WAIT_OBJECT_0) || !CloseHandle(thread));
+}
+
+static int pthread_mutex_init(pthread_mutex_t *restrict mutex,
+ const pthread_mutexattr_t *restrict attr)
+{
+ *mutex = CreateMutex(NULL, FALSE, NULL);
+ return (int)(*mutex == NULL);
+}
+
+static int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ return WaitForSingleObject(*mutex, INFINITE) == 0;
+}
+
+static int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+ return ReleaseMutex(*mutex) == 0;
+}
+
+static int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+ return CloseHandle(*mutex) == 0;
+}
+
+static int pthread_cond_init(pthread_cond_t *restrict cond,
+ const pthread_condattr_t *restrict attr)
+{
+ *cond = CreateEvent(NULL, FALSE, FALSE, NULL);
+ return (int)(*cond == NULL);
+}
+
+static int pthread_cond_wait(pthread_cond_t *restrict cond,
+ pthread_mutex_t *restrict mutex)
+{
+ SignalObjectAndWait(*mutex, *cond, INFINITE, FALSE);
+ return WaitForSingleObject(*mutex, INFINITE) == 0;
+}
+
+static int pthread_cond_destroy(pthread_cond_t *cond)
+{
+ return CloseHandle(*cond) == 0;
+}
+
+int pthread_cond_signal(pthread_cond_t *cond)
+{
+ return SetEvent(*cond) == 0;
+}
+
+#else
+#error no thread system available
+#endif
+
+typedef struct THThread_ {
+ pthread_t id;
+ int (*func)(void*);
+ void* data;
+ int status;
+} THThread;
+
+typedef struct THMutex_{
+ pthread_mutex_t id;
+ int refcount;
+} THMutex;
+
+typedef struct THCondition_ {
+ pthread_cond_t id;
+ int refcount;
+} THCondition;
+
+static void* thread_closure(void *data)
+{
+ THThread *thread = data;
+ thread->status = thread->func(thread->data);
+ return NULL;
+}
+
+THThread* THThread_new(int (*func)(void*), void *data)
+{
+ THThread *self = malloc(sizeof(THThread));
+ self->func = func;
+ self->data = data;
+ self->status = 0;
+ if(!self)
+ return NULL;
+ if(pthread_create(&self->id, NULL, thread_closure, self)) {
+ free(self);
+ return NULL;
+ }
+ return self;
+}
+
+long THThread_id(THThread *self)
+{
+ return (long)(self);
+}
+
+int THThread_free(THThread *self)
+{
+ int status = 1;
+ if(self) {
+ if(pthread_join(self->id, NULL))
+ return 1;
+ status = self->status;
+ free(self);
+ }
+ return status;
+}
+
+THMutex* THMutex_new(void)
+{
+ THMutex *self = malloc(sizeof(THMutex));
+ if(!self)
+ return NULL;
+ if(pthread_mutex_init(&self->id, NULL) != 0) {
+ free(self);
+ return NULL;
+ }
+ self->refcount = 1;
+ return self;
+}
+
+THMutex* THMutex_newWithId(long id)
+{
+ THMutex *self = (THMutex*)id;
+ THAtomicIncrementRef(&self->refcount);
+ return self;
+}
+
+long THMutex_id(THMutex *self)
+{
+ return (long)(self);
+}
+
+int THMutex_lock(THMutex *self)
+{
+ if(pthread_mutex_lock(&self->id) != 0)
+ return 1;
+ return 0;
+}
+
+int THMutex_unlock(THMutex *self)
+{
+ if(pthread_mutex_unlock(&self->id) != 0)
+ return 1;
+ return 0;
+}
+
+void THMutex_free(THMutex *self)
+{
+ if(self) {
+ if(THAtomicDecrementRef(&self->refcount)) {
+ pthread_mutex_destroy(&self->id);
+ free(self);
+ }
+ }
+}
+
+THCondition* THCondition_new(void)
+{
+ THCondition *self = malloc(sizeof(THCondition));
+ if(!self)
+ return NULL;
+ if(pthread_cond_init(&self->id, NULL)) {
+ free(self);
+ return NULL;
+ }
+ self->refcount = 1;
+ return self;
+}
+
+THCondition* THCondition_newWithId(long id)
+{
+ THCondition *self = (THCondition*)id;
+ THAtomicIncrementRef(&self->refcount);
+ return self;
+}
+
+long THCondition_id(THCondition *self)
+{
+ return (long)(self);
+}
+
+int THCondition_signal(THCondition *self)
+{
+ if(pthread_cond_signal(&self->id))
+ return 1;
+ return 0;
+}
+
+int THCondition_wait(THCondition *self, THMutex *mutex)
+{
+ if(pthread_cond_wait(&self->id, &mutex->id))
+ return 1;
+ return 0;
+}
+
+void THCondition_free(THCondition *self)
+{
+ if(self) {
+ if(THAtomicDecrementRef(&self->refcount)) {
+ pthread_cond_destroy(&self->id);
+ }
+ }
+}
+
+#endif
diff --git a/lib/THThread.h b/lib/THThread.h
new file mode 100644
index 0000000..0b086fb
--- /dev/null
+++ b/lib/THThread.h
@@ -0,0 +1,26 @@
+#ifndef TH_THREAD_INC
+#define TH_THREAD_INC
+
+typedef struct THThread_ THThread;
+typedef struct THMutex_ THMutex;
+typedef struct THCondition_ THCondition;
+
+THThread* THThread_new(int (*closure)(void*), void *data);
+long THThread_id(THThread *self);
+int THThread_free(THThread *self);
+
+THMutex* THMutex_new(void);
+THMutex* THMutex_newWithId(long id);
+long THMutex_id(THMutex *self);
+int THMutex_lock(THMutex *self);
+int THMutex_unlock(THMutex *self);
+void THMutex_free(THMutex *self);
+
+THCondition* THCondition_new(void);
+THCondition* THCondition_newWithId(long id);
+long THCondition_id(THCondition *self);
+int THCondition_signal(THCondition *self);
+int THCondition_wait(THCondition *self, THMutex *mutex);
+void THCondition_free(THCondition *self);
+
+#endif
diff --git a/lib/init.c b/lib/init.c
new file mode 100644
index 0000000..5f7723a
--- /dev/null
+++ b/lib/init.c
@@ -0,0 +1,10 @@
+#include "threads.c"
+#include "queue.c"
+
+int luaopen_libthreads(lua_State *L)
+{
+ lua_newtable(L);
+ thread_init_pkg(L);
+ queue_init_pkg(L);
+ return 1;
+}
diff --git a/lib/luaTHRD.h b/lib/luaTHRD.h
new file mode 100644
index 0000000..3760bdb
--- /dev/null
+++ b/lib/luaTHRD.h
@@ -0,0 +1,84 @@
+#ifndef LUA_THRD_INC
+#define LUA_THRD_INC
+
+static int luaTHRD_pushudata(lua_State *L, void *ptr, const char* typename)
+{
+ void **udata = lua_newuserdata(L, sizeof(void*));
+ if(udata) {
+ *udata = ptr;
+ luaL_getmetatable(L, typename);
+ lua_setmetatable(L, -2);
+ return 1;
+ }
+ return 0;
+}
+
+static void *luaTHRD_checkudata(lua_State *L, int narg, const char *typename)
+{
+ void **udata = luaL_checkudata(L, narg, typename);
+ if(udata)
+ return *udata;
+ else
+ return NULL;
+}
+
+static void *luaTHRD_toudata(lua_State *L, int narg, const char *typename)
+{
+ void **udata = lua_touserdata(L, narg);
+ if(udata) {
+ if(lua_getmetatable(L, -1)) {
+ luaL_getmetatable(L, typename);
+ if(lua_equal(L, -1, -2)) {
+ lua_pop(L, 2);
+ return *udata;
+ }
+ else {
+ lua_pop(L, 2);
+ return NULL;
+ }
+ }
+ else
+ return NULL;
+ }
+ else
+ return NULL;
+}
+
+static int luaTHRD_ctor(lua_State *L)
+{
+ if(!lua_istable(L, 1)) /* dummy ctor table */
+ luaL_error(L, "ctor: table expected");
+ lua_getmetatable(L, 1);
+ lua_remove(L, 1); /* dummy ctor table */
+ if(!lua_istable(L, -1))
+ luaL_error(L, "ctor: no metatable found");
+ lua_pushstring(L, "__new");
+ lua_rawget(L, -2);
+ lua_remove(L, -2); /* forget about metatable */
+ if(!lua_isfunction(L, -1))
+ luaL_error(L, "ctor: __new appears to be not a function");
+ lua_insert(L, 1); /* ctor first, arguments follow */
+ lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
+ return lua_gettop(L);
+}
+
+static void luaTHRD_pushctortable(lua_State *L, lua_CFunction ctor, const char* typename)
+{
+ lua_newtable(L); /* empty useless dude */
+ lua_newtable(L); /* metatable of the dude */
+ lua_pushstring(L, "__index");
+ luaL_getmetatable(L, typename);
+ lua_rawset(L, -3);
+ lua_pushstring(L, "__newindex");
+ luaL_getmetatable(L, typename);
+ lua_rawset(L, -3);
+ lua_pushstring(L, "__new"); /* __call will look into there */
+ lua_pushcfunction(L, ctor);
+ lua_rawset(L, -3);
+ lua_pushstring(L, "__call"); /* pop the table and calls __new */
+ lua_pushcfunction(L, luaTHRD_ctor);
+ lua_rawset(L, -3);
+ lua_setmetatable(L, -2);
+}
+
+#endif
diff --git a/lib/queue.c b/lib/queue.c
new file mode 100644
index 0000000..9ed7fa3
--- /dev/null
+++ b/lib/queue.c
@@ -0,0 +1,383 @@
+#include "TH.h" /* for THCharStorage */
+#include "luaT.h" /* for handling THCHarStorage */
+#include "luaTHRD.h"
+#include "THThread.h"
+#include <lua.h>
+#include <lualib.h>
+#include <lualib.h>
+
+
+typedef struct THQueue_ {
+ THMutex *mutex;
+ THCondition *notfull;
+ THCondition *notempty;
+ THCharStorage **callbacks;
+ THCharStorage **args;
+ char* serialize;
+
+ int head;
+ int tail;
+ int isempty;
+ int isfull;
+ int size;
+ int refcount;
+} THQueue;
+
+static int queue_new(lua_State *L)
+{
+ THQueue *queue = NULL;
+ THQueue **queue_udata = NULL;
+
+ if(lua_gettop(L) == 1) {
+
+ queue = (THQueue*)luaL_checkinteger(L, 1);
+ THMutex_lock(queue->mutex);
+ queue->refcount = queue->refcount + 1;
+ THMutex_unlock(queue->mutex);
+
+ } else if(lua_gettop(L) == 2) {
+
+ int size = luaL_checkint(L, 1);
+ const char *serialize = luaL_checkstring(L, 2);
+ size_t serialize_len;
+ lua_tolstring(L, 2, &serialize_len);
+
+ queue = calloc(1, sizeof(THQueue)); /* zeroed */
+ if(!queue)
+ goto outofmem;
+
+ queue->mutex = THMutex_new();
+ queue->notfull = THCondition_new();
+ queue->notempty = THCondition_new();
+ queue->callbacks = calloc(size, sizeof(THCharStorage*));
+ queue->args = calloc(size, sizeof(THCharStorage*));
+ queue->serialize = malloc(serialize_len+1);
+ if(queue->serialize)
+ memcpy(queue->serialize, serialize, serialize_len+1);
+
+ queue->head = 0;
+ queue->tail = 0;
+ queue->isempty = 1;
+ queue->isfull = 0;
+ queue->size = size;
+ queue->refcount = 1;
+
+ if(!queue->mutex || !queue->notfull || !queue->notempty
+ || !queue->callbacks || !queue->args || !queue->serialize)
+ goto outofmemfree;
+
+ } else
+ luaL_error(L, "threads: queue new invalid arguments");
+
+ if(!luaTHRD_pushudata(L, queue, "threads.Queue"))
+ goto outofmemfree;
+
+ return 1;
+
+
+ outofmemfree:
+ THMutex_free(queue->mutex);
+ THCondition_free(queue->notfull);
+ THCondition_free(queue->notempty);
+ free(queue->callbacks);
+ free(queue->args);
+ free(queue->serialize);
+ free(queue);
+ outofmem:
+ luaL_error(L, "threads: queue new out of memory");
+ return 0;
+}
+
+static int queue_free(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ if(THAtomicDecrementRef(&queue->refcount))
+ {
+ int i;
+ THMutex_free(queue->mutex);
+ THCondition_free(queue->notfull);
+ THCondition_free(queue->notempty);
+ for(i = 0; i < queue->size; i++) {
+ if(queue->callbacks[i])
+ THCharStorage_free(queue->callbacks[i]);
+ if(queue->args[i])
+ THCharStorage_free(queue->args[i]);
+ }
+ free(queue->serialize);
+ free(queue->callbacks);
+ free(queue->args);
+ free(queue);
+ }
+ return 0;
+}
+
+static int queue_retain(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ THAtomicIncrementRef(&queue->refcount);
+ return 0;
+}
+
+static int queue_get_mutex(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ return luaTHRD_pushudata(L, queue->mutex, "threads.Mutex");
+}
+
+static int queue_get_notfull(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ return luaTHRD_pushudata(L, queue->notfull, "threads.Condition");
+}
+
+static int queue_get_notempty(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ return luaTHRD_pushudata(L, queue->notempty, "threads.Condition");
+}
+
+static int queue_get_serialize(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ lua_pushstring(L, queue->serialize);
+ return 1;
+}
+
+static int queue_get_head(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ lua_pushnumber(L, queue->head);
+ return 1;
+}
+
+static int queue_get_tail(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ lua_pushnumber(L, queue->tail);
+ return 1;
+}
+
+static int queue_get_isempty(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ lua_pushnumber(L, queue->isempty);
+ return 1;
+}
+
+static int queue_get_isfull(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ lua_pushnumber(L, queue->isfull);
+ return 1;
+}
+
+static int queue_get_size(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ lua_pushnumber(L, queue->size);
+ return 1;
+}
+
+static int queue__index(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ lua_getmetatable(L, 1);
+ if(lua_isstring(L, 2)) {
+ lua_pushstring(L, "__get");
+ lua_rawget(L, -2);
+ lua_pushvalue(L, 2);
+ lua_rawget(L, -2);
+ if(lua_isfunction(L, -1)) {
+ lua_pushvalue(L, 1);
+ lua_call(L, 1, 1);
+ return 1;
+ }
+ else {
+ lua_pop(L, 2);
+ }
+ }
+ lua_insert(L, -2);
+ lua_rawget(L, -2);
+ return 1;
+}
+
+static int queue_callback(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ int idx = luaL_checkint(L, 2);
+ luaL_argcheck(L, idx >= 0 && idx < queue->size, 2, "out of range");
+ if(lua_gettop(L) == 2) {
+ THCharStorage *storage = NULL;
+ if((storage = queue->callbacks[idx])) {
+ THCharStorage_retain(storage);
+ luaT_pushudata(L, storage, "torch.CharStorage");
+ return 1;
+ }
+ else
+ return 0;
+ }
+ else if(lua_gettop(L) == 3) {
+ THCharStorage *storage = luaT_checkudata(L, 3, "torch.CharStorage"); /* DEBUG: might be luaT for torch objects */
+ if(queue->callbacks[idx]) {
+ THCharStorage_free(queue->callbacks[idx]);
+ }
+ queue->callbacks[idx] = storage;
+ THCharStorage_retain(storage);
+ return 0;
+ }
+ else
+ luaL_error(L, "invalid arguments");
+ return 0;
+}
+
+static int queue_arg(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ int idx = luaL_checkint(L, 2);
+ luaL_argcheck(L, idx >= 0 && idx < queue->size, 2, "out of range");
+ if(lua_gettop(L) == 2) {
+ THCharStorage *storage = NULL;
+ if((storage = queue->args[idx])) {
+ THCharStorage_retain(storage);
+ luaT_pushudata(L, storage, "torch.CharStorage");
+ return 1;
+ }
+ else
+ return 0;
+ }
+ else if(lua_gettop(L) == 3) {
+ THCharStorage *storage = luaT_checkudata(L, 3, "torch.CharStorage"); /* DEBUG: might be luaT for torch objects */
+ if(queue->args[idx])
+ THCharStorage_free(queue->args[idx]);
+ queue->args[idx] = storage;
+ THCharStorage_retain(storage);
+ return 0;
+ }
+ else
+ luaL_error(L, "invalid arguments");
+ return 0;
+}
+
+
+/* */
+
+static int queue_set_head(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ int value = luaL_checkint(L, 2);
+ queue->head = value;
+ return 0;
+}
+
+static int queue_set_tail(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ int value = luaL_checkint(L, 2);
+ queue->tail = value;
+ return 0;
+}
+
+static int queue_set_isempty(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ int value = luaL_checkint(L, 2);
+ queue->isempty = value;
+ return 0;
+}
+
+static int queue_set_isfull(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ int value = luaL_checkint(L, 2);
+ queue->isfull = value;
+ return 0;
+}
+
+static int queue__newindex(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ if(lua_gettop(L) != 3)
+ luaL_error(L, "invalid arguments");
+
+ lua_getmetatable(L, 1);
+ if(lua_isstring(L, 2)) {
+ lua_pushstring(L, "__set");
+ lua_rawget(L, -2);
+ lua_pushvalue(L, 2);
+ lua_rawget(L, -2);
+ if(lua_isfunction(L, -1)) {
+ lua_pushvalue(L, 1);
+ lua_pushvalue(L, 3);
+ lua_call(L, 2, 0);
+ return 0;
+ }
+ else
+ luaL_error(L, "invalid argument");
+ }
+ luaL_error(L, "invalid argument");
+ return 0;
+}
+
+static int queue_id(lua_State *L)
+{
+ THQueue *queue = luaTHRD_checkudata(L, 1, "threads.Queue");
+ lua_pushinteger(L, (long)queue);
+ return 1;
+}
+
+static const struct luaL_Reg queue__ [] = {
+ {"new", queue_new},
+ {"id", queue_id},
+ {"retain", queue_retain},
+ {"free", queue_free},
+ {"callback", queue_callback},
+ {"arg", queue_arg},
+ {"__gc", queue_free},
+ {"__index", queue__index},
+ {"__newindex", queue__newindex},
+ {NULL, NULL}
+};
+
+static const struct luaL_Reg queue_get__ [] = {
+ {"mutex", queue_get_mutex},
+ {"notfull", queue_get_notfull},
+ {"notempty", queue_get_notempty},
+ {"serialize", queue_get_serialize},
+ {"head", queue_get_head},
+ {"tail", queue_get_tail},
+ {"isempty", queue_get_isempty},
+ {"isfull", queue_get_isfull},
+ {"size", queue_get_size},
+ {NULL, NULL}
+};
+
+static const struct luaL_Reg queue_set__ [] = {
+ {"head", queue_set_head},
+ {"tail", queue_set_tail},
+ {"isempty", queue_set_isempty},
+ {"isfull", queue_set_isfull},
+ {NULL, NULL}
+};
+
+static void queue_init_pkg(lua_State *L)
+{
+ if(!luaL_newmetatable(L, "threads.Queue"))
+ luaL_error(L, "threads: threads.Queue type already exists");
+ luaL_register(L, NULL, queue__);
+
+ lua_pushstring(L, "__get");
+ lua_newtable(L);
+ luaL_register(L, NULL, queue_get__);
+ lua_rawset(L, -3);
+
+ lua_pushstring(L, "__set");
+ lua_newtable(L);
+ luaL_register(L, NULL, queue_set__);
+ lua_rawset(L, -3);
+
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "Queue");
+ luaTHRD_pushctortable(L, queue_new, "threads.Queue");
+ lua_rawset(L, -3);
+}
diff --git a/lib/threads.c b/lib/threads.c
new file mode 100644
index 0000000..b670540
--- /dev/null
+++ b/lib/threads.c
@@ -0,0 +1,263 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <luaT.h>
+#include <string.h>
+
+#include "THThread.h"
+#include "luaTHRD.h"
+
+#include <lua.h>
+#include <lualib.h>
+
+static int newthread(void *code_)
+{
+ char *code = code_;
+ lua_State *L = luaL_newstate();
+
+ if(!L) {
+ printf("THREAD FATAL ERROR: could not create lua state\n");
+ return -1;
+ }
+ luaL_openlibs(L);
+
+ long addr = (long)code;
+ if(luaL_loadstring(L, code)) {
+ printf("FATAL THREAD PANIC: (loadstring) %s\n", lua_tolstring(L, -1, NULL));
+ free(code);
+ lua_close(L);
+ return -1;
+ }
+ free(code);
+ if(lua_pcall(L, 0, 0, 0)) {
+ printf("FATAL THREAD PANIC: (pcall) %s\n", lua_tolstring(L, -1, NULL));
+ lua_close(L);
+ return -1;
+ }
+
+ lua_close(L);
+ return 0;
+}
+
+static int thread_new(lua_State *L)
+{
+ THThread *thread = NULL;
+ size_t len = 0;
+ const char *code = luaL_checklstring(L, 1, &len);
+ char *code_dup = malloc(len+1);
+ if(!code_dup)
+ luaL_error(L, "threads: out of memory");
+ memcpy(code_dup, code, len+1);
+
+ thread = THThread_new(newthread, (void*)code_dup);
+ if(!thread)
+ luaL_error(L, "threads: thread new failed");
+ luaTHRD_pushudata(L, thread, "threads.Thread");
+
+ return 1;
+}
+
+static int thread_tostring(lua_State *L)
+{
+ char str[128];
+ THThread *thread = luaTHRD_checkudata(L, 1, "threads.Thread");
+ snprintf(str, 128, "threads.Thread <%lx>", THThread_id(thread));
+ lua_pushstring(L, str);
+ return 1;
+}
+
+static int thread_id(lua_State *L)
+{
+ THThread *thread = luaTHRD_checkudata(L, 1, "threads.Thread");
+ lua_pushinteger(L, THThread_id(thread));
+ return 1;
+}
+
+static int thread_free(lua_State *L)
+{
+ THThread *thread = luaTHRD_checkudata(L, 1, "threads.Thread");
+ THThread_free(thread);
+ return 0;
+}
+
+static int mutex_new(lua_State *L)
+{
+ THMutex *mutex = NULL;
+ if(lua_gettop(L) == 0) {
+ mutex = THMutex_new();
+ }
+ else if(lua_gettop(L) == 1) {
+ long id = luaL_checklong(L, 1);
+ mutex = THMutex_newWithId(id);
+ }
+ else
+ luaL_error(L, "threads: mutex new invalid arguments");
+ if(!mutex)
+ luaL_error(L, "threads: mutex new failed");
+ luaTHRD_pushudata(L, mutex, "threads.Mutex");
+ return 1;
+}
+
+static int mutex_tostring(lua_State *L)
+{
+ char str[128];
+ THMutex *mutex = luaTHRD_checkudata(L, 1, "threads.Mutex");
+ snprintf(str, 128, "threads.Mutex <%lx>", THMutex_id(mutex));
+ lua_pushstring(L, str);
+ return 1;
+}
+
+static int mutex_id(lua_State *L)
+{
+ THMutex *mutex = luaTHRD_checkudata(L, 1, "threads.Mutex");
+ lua_pushinteger(L, THMutex_id(mutex));
+ return 1;
+}
+
+static int mutex_lock(lua_State *L)
+{
+ THMutex *mutex = luaTHRD_checkudata(L, 1, "threads.Mutex");
+ if(THMutex_lock(mutex))
+ luaL_error(L, "threads: mutex lock failed");
+ return 0;
+}
+
+static int mutex_unlock(lua_State *L)
+{
+ THMutex *mutex = luaTHRD_checkudata(L, 1, "threads.Mutex");
+ if(THMutex_unlock(mutex))
+ luaL_error(L, "threads: mutex unlock failed");
+ return 0;
+}
+
+static int mutex_free(lua_State *L)
+{
+ THMutex *mutex = luaTHRD_checkudata(L, 1, "threads.Mutex");
+ THMutex_free(mutex);
+ return 0;
+}
+
+static int condition_new(lua_State *L)
+{
+ THCondition *condition = NULL;
+ if(lua_gettop(L) == 0) {
+ condition = THCondition_new();
+ }
+ else if(lua_gettop(L) == 1) {
+ long id = luaL_checklong(L, 1);
+ condition = THCondition_newWithId(id);
+ }
+ else
+ luaL_error(L, "threads: condition new invalid arguments");
+ if(!condition)
+ luaL_error(L, "threads: condition new failed");
+ luaTHRD_pushudata(L, condition, "threads.Condition");
+ return 1;
+}
+
+static int condition_tostring(lua_State *L)
+{
+ char str[128];
+ THCondition *condition = luaTHRD_checkudata(L, 1, "threads.Condition");
+ snprintf(str, 128, "threads.Condition <%lx>", THCondition_id(condition));
+ lua_pushstring(L, str);
+ return 1;
+}
+
+static int condition_id(lua_State *L)
+{
+ THCondition *condition = luaTHRD_checkudata(L, 1, "threads.Condition");
+ lua_pushinteger(L, THCondition_id(condition));
+ return 1;
+}
+
+static int condition_free(lua_State *L)
+{
+ THCondition *condition = luaTHRD_checkudata(L, 1, "threads.Condition");
+ if(!condition)
+ luaL_error(L, "threads: condition free failed");
+ return 0;
+}
+
+static int condition_signal(lua_State *L)
+{
+ THCondition *condition = luaTHRD_checkudata(L, 1, "threads.Condition");
+ if(THCondition_signal(condition))
+ luaL_error(L, "threads: condition signal failed");
+ return 0;
+}
+
+static int condition_wait(lua_State *L)
+{
+ THCondition *condition = luaTHRD_checkudata(L, 1, "threads.Condition");
+ THMutex *mutex = luaTHRD_checkudata(L, 2, "threads.Mutex");
+ if(THCondition_wait(condition, mutex))
+ luaL_error(L, "threads: condition wait failed");
+ return 0;
+}
+
+static const struct luaL_Reg thread__ [] = {
+ {"new", thread_new},
+ {"__tostring", thread_tostring},
+ {"id", thread_id},
+ {"free", thread_free},
+ {NULL, NULL}
+};
+
+static const struct luaL_Reg mutex__ [] = {
+ {"new", mutex_new},
+ {"__tostring", mutex_tostring},
+ {"id", mutex_id},
+ {"lock", mutex_lock},
+ {"unlock", mutex_unlock},
+ {"free", mutex_free},
+ {NULL, NULL}
+};
+
+static const struct luaL_Reg condition__ [] = {
+ {"new", condition_new},
+ {"__tostring", condition_tostring},
+ {"id", condition_id},
+ {"signal", condition_signal},
+ {"wait", condition_wait},
+ {"free", condition_free},
+ {NULL, NULL}
+};
+
+static void thread_init_pkg(lua_State *L)
+{
+ if(!luaL_newmetatable(L, "threads.Thread"))
+ luaL_error(L, "threads: threads.Thread type already exists");
+ luaL_register(L, NULL, thread__);
+ lua_pushstring(L, "__index");
+ lua_pushvalue(L, -2);
+ lua_rawset(L, -3);
+ lua_pop(L, 1);
+
+ if(!luaL_newmetatable(L, "threads.Mutex"))
+ luaL_error(L, "threads: threads.Mutex type already exists");
+ luaL_register(L, NULL, mutex__);
+ lua_pushstring(L, "__index");
+ lua_pushvalue(L, -2);
+ lua_rawset(L, -3);
+ lua_pop(L, 1);
+
+ if(!luaL_newmetatable(L, "threads.Condition"))
+ luaL_error(L, "threads: threads.Condition type already exists");
+ luaL_register(L, NULL, condition__);
+ lua_pushstring(L, "__index");
+ lua_pushvalue(L, -2);
+ lua_rawset(L, -3);
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "Thread");
+ luaTHRD_pushctortable(L, thread_new, "threads.Thread");
+ lua_rawset(L, -3);
+
+ lua_pushstring(L, "Mutex");
+ luaTHRD_pushctortable(L, mutex_new, "threads.Mutex");
+ lua_rawset(L, -3);
+
+ lua_pushstring(L, "Condition");
+ luaTHRD_pushctortable(L, condition_new, "threads.Condition");
+ lua_rawset(L, -3);
+}