lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


> Is anyone doing this, or are you looking for a volunteer?

I have a primitive implementation of pthreads using these new facilities. I 
am not sure whether it is still working with this Lua code (I made it some 
time ago), but the main ideas are there. You must put the .h file as the 
LUA_USER_H; it redefines LUA_LOCK and LUA_UNLOCK (this is a first 
incompatibility; now those macros are written in lower case...). 
Moreover, there is still the possibility of some syncronization problems 
during garbage collection. Use it at your own risk!

-- Roberto

#include <pthread.h>

#define LUA_LOCK(L)	pthread_mutex_lock(&mutex)
#define LUA_UNLOCK(L)	pthread_mutex_unlock(&mutex)


extern pthread_mutex_t mutex;

void openthreads (lua_State *L);


#define LUA_USERINIT(L)		(openstdlibs(L), openthreads(L))
#include <assert.h>
#include <pthread.h>

#include "../lua.h"
#include "../lauxlib.h"


pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;



static void *init_thread (void *arg) {
  lua_State *L = (lua_State *)arg;
  int n = lua_getn(L, 1);  /* number of arguments */
  int i;
  for (i=1; i<=n; i++)  /* push arguments */
    lua_rawgeti(L, 1, i);
  lua_remove(L, 1);  /* table is garbage now */
  pthread_detach(pthread_self());
  lua_call(L, n, 0);
  return NULL;
}


static int newthread (lua_State *L) {
  lua_State *NL;
  int ref;
  pthread_t thread;
  luaL_checktype(L, 1, LUA_TFUNCTION);
  luaL_checktype(L, 2, LUA_TTABLE);
  NL = lua_open(L, luaL_opt_int(L, 3, 0));
  if (NL == NULL)
    lua_error(L, "cannot create new stack");
  lua_settop(L, 2);  /* remove eventual stacksize */
  /* move table and function from L to NL */
  ref = lua_ref(L, 1);
  lua_getref(NL, ref);
  lua_unref(L, ref);  
  ref = lua_ref(L, 1);
  lua_getref(NL, ref);
  lua_unref(L, ref);  
  if (pthread_create(&thread, NULL, init_thread, NL) != 0)
    lua_error(L, "cannot create new thread");
  return 0;
}


static int newmutex (lua_State *L) {
  pthread_mutex_t *mtx =
            (pthread_mutex_t *)lua_newuserdata(L, sizeof(pthread_mutex_t));
  if (pthread_mutex_init(mtx, NULL) != 0)
    lua_error(L, "unable to create mutex");
  lua_settag(L, lua_type2tag(L, "pthread_Mutex"));
  return 1;
}


static int mdestroy (lua_State *L) {
  pthread_mutex_t *mtx = (pthread_mutex_t *)lua_touserdata(L, 1);
  pthread_mutex_destroy(mtx);
  return 0;
}


static int mlock (lua_State *L) {
  pthread_mutex_t *mtx =
            (pthread_mutex_t *)luaL_check_userdata(L, 1, "pthread_Mutex");
  if (pthread_mutex_lock(mtx) != 0)
    lua_error(L, "unable to lock mutex");
  return 0;
}


static int munlock (lua_State *L) {
  pthread_mutex_t *mtx =
            (pthread_mutex_t *)luaL_check_userdata(L, 1, "pthread_Mutex");
  if (pthread_mutex_unlock(mtx) != 0)
    lua_error(L, "unable to unlock mutex");
  return 0;
}


struct Cond {
  pthread_cond_t cond;  /* condition */
  pthread_mutex_t *mtx;  /* corresponding mutex */
  int mtxref;  /* reference to mutex (to avoid GC) */
};


static int newcond (lua_State *L) {
  struct Cond *cond = (struct Cond *)lua_newuserdata(L, sizeof(struct Cond));
  cond->mtx = (pthread_mutex_t *)luaL_check_userdata(L, 1, "pthread_Mutex");
  lua_pushvalue(L, 1);
  cond->mtxref = lua_ref(L, 1);  /* lock mutex */
  if (pthread_cond_init(&cond->cond, NULL) != 0)
    lua_error(L, "unable to create condition");
  lua_settag(L, lua_type2tag(L, "pthread_Condition"));
  return 1;
}


static int cwait (lua_State *L) {
  struct Cond *cond =
      (struct Cond *)luaL_check_userdata(L, 1, "pthread_Condition");
  if (pthread_cond_wait(&cond->cond, cond->mtx) != 0)
    lua_error(L, "unable to wait");
  return 0;
}


static int csignal (lua_State *L) {
  int status;
  struct Cond *cond =
      (struct Cond *)luaL_check_userdata(L, 1, "pthread_Condition");
  if (*luaL_opt_string(L, 2, "a") == 'a')
    status = pthread_cond_broadcast(&cond->cond);
  else
    status = pthread_cond_signal(&cond->cond);
  if (status != 0)
    lua_error(L, "unable to signal");
  return 0;
}


static int cdestroy (lua_State *L) {
  struct Cond *cond = (struct Cond *)lua_touserdata(L, 1);
  pthread_cond_destroy(&cond->cond);
  lua_unref(L, cond->mtxref);
  return 0;
}


static int gettab (lua_State *L) {
  lua_insert(L, 1);
  lua_gettable(L, 1);
  return 1;
}


static const struct luaL_reg lib[] = {
  {"newthread", newthread},
  {"newmutex", newmutex},
  {"newcond", newcond}
};


static const struct luaL_reg muops[] = {
  {"lock", mlock},
  {"unlock", munlock},
  {NULL, NULL}
};


static const struct luaL_reg cndops[] = {
  {"wait", cwait},
  {"signal", csignal},
  {NULL, NULL}
};


static void createmethods (lua_State *L, const struct luaL_reg *m, int tag) {
  lua_newtable(L);
  for (;m->name; m++) {
    lua_pushstring(L, m->name);
    lua_pushcfunction(L, m->func);
    lua_settable(L, -3);
  }
  lua_pushcclosure(L, gettab, 1);
  lua_settagmethod(L, tag, "gettable");
}


void openthreads (lua_State *L) {
  int mtx = lua_newtype(L, "pthread_Mutex", LUA_TUSERDATA);
  int cnd = lua_newtype(L, "pthread_Condition", LUA_TUSERDATA);
  lua_pushcfunction(L, mdestroy);
  lua_settagmethod(L, mtx, "gc");
  lua_pushcfunction(L, cdestroy);
  lua_settagmethod(L, cnd, "gc");
  createmethods(L, muops, mtx);
  createmethods(L, cndops, cnd);
  luaL_openl(L, lib);
}