Skip to content

Commit

Permalink
update thread
Browse files Browse the repository at this point in the history
  • Loading branch information
mcfriend99 committed Oct 15, 2024
1 parent 08514c9 commit 5c69420
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 37 deletions.
109 changes: 79 additions & 30 deletions libs/thread.b
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ def _is_not_main_thread(id) {id
}

/**
* The thread class exposes methods to manage creating, running,
* and controlling threads.
*
* @class
*/
class Thread {

var _fn
var _fn_arity
var _delegate
var _delegate_arity

var _args
var _name
Expand All @@ -37,17 +40,17 @@ class Thread {
var _detached = false

/**
* The function passed to the constructor may accept zero or more
* parameters. When it accepts no parameter, the function will be
* called without any argument when run otherwise, it will be
* called with as many argument as it can receive.
* The delegate function passed to the constructor may accept zero
* or more parameters. When it accepts no parameter, the function
* will be called without any argument when run otherwise, it will
* be called with as many argument as it can receive.
*
* When a function accepts arguments, the first argument passed
* When a delegate accepts arguments, the first argument passed
* will always be the thread object itself followed by the arguments
* it received from start.
*
* For example, in the following thread execution, the first
* parameter _t_ in the function will receive the thread object
* parameter _t_ in the delegate will receive the thread object
* itself.
*
* ```blade
Expand All @@ -58,10 +61,11 @@ class Thread {
* th.start(21)
* ```
*
* The function doesn't raise an exception because parameter _t_ never
* received the `start()` argument but the thread itself. In the next
* example, the function accepts the start argument. Note that the start
* argument was received starting from the second argument.
* The delegate function doesn't raise an exception because parameter
* _t_ never received the `start()` argument but the thread itself.
* In the next example, the function accepts the start argument. Note
* that the start argument was received starting from the second
* argument.
*
* ```blade
* var th = Thread(@(t, balance) {
Expand All @@ -71,15 +75,26 @@ class Thread {
* th.start(21)
* ```
*
* @params function fn
* The optional second parameter allows us to set the size of the stack
* used for the thread when started.
*
* @param function delegate
* @param number? stack_size
* @constructor
*/
Thread(fn) {
if !is_function(fn)
raise Exception('function(1..) expected, ${typeof(fn)} given')
Thread(delegate, stack_size) {
if !is_function(delegate)
raise Exception('function(1..) expected, ${typeof(delegate)} given')

self._fn = fn
self._fn_arity = reflect.get_function_metadata(fn).arity
self._delegate = delegate
self._delegate_arity = reflect.get_function_metadata(delegate).arity

# set stack size if given.
# we're falling back on the type check done by set_stack_size
# here...
if stack_size != nil {
self.set_stack_size(stack_size)
}
}

/**
Expand All @@ -92,7 +107,7 @@ class Thread {
*
* > **NOTE:** A thread can only be started once.
*
* @params any... args
* @param any... args
*/
start(...) {
self.start_from_list(__args__)
Expand All @@ -101,7 +116,7 @@ class Thread {
/**
* Same as `start()` but takes the argument from a list instead.
*
* @params list args
* @param list args
*/
start_from_list(args) {
if !is_list(args)
Expand All @@ -115,9 +130,9 @@ class Thread {
args = [self] + args

# only pass on arguments that the run function is able to accept.
args = args[0,self._fn_arity]
args = args[0,self._delegate_arity]

self._ptr = _thread.new(self._fn, args)
self._ptr = _thread.new(self._delegate, args)
self._started = _thread.start(self._ptr, self._size)
}

Expand All @@ -133,7 +148,13 @@ class Thread {
*/
dispose() {
assert self._ptr, 'thread not started'
return _thread.dispose(self._ptr)

if _thread.dispose(self._ptr) {
self._ptr = nil
return true
}

return false
}

/**
Expand Down Expand Up @@ -202,9 +223,6 @@ class Thread {
self._joined = false
}

# TODO: Implement
try_await() {}

/**
* Causes the current thread to sleep for the specified number of seconds.
*
Expand Down Expand Up @@ -331,19 +349,50 @@ class Thread {
return _thread.get_id()
}

# TODO: Implement
is_alive() {}
/**
* Returns true if the thread is started and alive (running)
* or false if not.
*
* @returns bool
*/
is_alive() {
if self._ptr {
return self._started and _thread.is_alive(self._ptr)
}

return false
}
}


/**
* Returns a new instance of Thread.
*
* @param function delegate
* @param number? stack_size
* @see Constructor
* @returns Thread
*/
def thread(delegate, stack_size) {
return Thread(delegate, stack_size)
}


def start(function, args) {
/**
* Creates a new thread and automatically starts the thread
* using the default options and arguments.
*
* @param function delegate
* @param list args
*/
def start(delegate, args) {
if args == nil args = []

# we're deliberately not checking the arguments here
# because the thread initializer and start_from_list function
# will take care of that on their own.

var thread = Thread(function)
var thread = Thread(delegate)
thread.start_from_list(args)
return thread
}
26 changes: 19 additions & 7 deletions src/standard/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,11 +247,14 @@ DECLARE_MODULE_METHOD(thread__set_name) {
RETURN_BOOL(pthread_setname_np(AS_C_STRING(args[1])) == 0);
#else
b_thread_handle *thread = AS_PTR(args[0])->pointer;
if(thread != NULL && thread->vm != NULL) {
# if defined(PTHREAD_MAX_NAMELEN_NP) && PTHREAD_MAX_NAMELEN_NP == 16
RETURN_BOOL(pthread_setname_np(thread->thread, AS_C_STRING(args[1]), NULL) == 0);
RETURN_BOOL(pthread_setname_np(thread->thread, AS_C_STRING(args[1]), NULL) == 0);
# else
RETURN_BOOL(pthread_setname_np(thread->thread, AS_C_STRING(args[1])) == 0);
RETURN_BOOL(pthread_setname_np(thread->thread, AS_C_STRING(args[1])) == 0);
# endif
}
RETURN_FALSE;
#endif
}

Expand All @@ -260,16 +263,17 @@ DECLARE_MODULE_METHOD(thread__get_name) {
ENFORCE_ARG_TYPE(get_name, 0, IS_PTR);
b_thread_handle *thread = AS_PTR(args[0])->pointer;

char buffer[255];
if(pthread_getname_np(thread->thread, buffer, 255) == 0) {
RETURN_STRING(buffer);
if(thread != NULL && thread->vm != NULL) {
char buffer[255];
if(pthread_getname_np(thread->thread, buffer, 255) == 0) {
RETURN_STRING(buffer);
}
}

RETURN_VALUE(EMPTY_STRING_VAL);
}

uint64_t get_thread_id(void)
{
uint64_t get_thread_id(void) {
#if defined(__linux__)
return syscall(SYS_gettid);
#elif defined(__FreeBSD__)
Expand Down Expand Up @@ -300,6 +304,13 @@ DECLARE_MODULE_METHOD(thread__yield) {
RETURN_BOOL(sched_yield() == 0);
}

DECLARE_MODULE_METHOD(thread__is_alive) {
ENFORCE_ARG_COUNT(is_alive, 1);
ENFORCE_ARG_TYPE(get_name, 0, IS_PTR);
b_thread_handle *thread = AS_PTR(args[0])->pointer;
RETURN_BOOL(thread != NULL && thread->vm != NULL);
}

CREATE_MODULE_LOADER(thread) {
static b_func_reg module_functions[] = {
{"new", false, GET_MODULE_METHOD(thread__new)},
Expand All @@ -311,6 +322,7 @@ CREATE_MODULE_LOADER(thread) {
{"set_name", false, GET_MODULE_METHOD(thread__set_name)},
{"get_name", false, GET_MODULE_METHOD(thread__get_name)},
{"get_id", false, GET_MODULE_METHOD(thread__get_id)},
{"is_alive", false, GET_MODULE_METHOD(thread__is_alive)},
{NULL, false, NULL},
};

Expand Down

0 comments on commit 5c69420

Please sign in to comment.