5 #ifndef KRK_DISABLE_THREADS
12 #if defined(__linux__)
13 # include <sys/syscall.h>
14 # define gettid() syscall(SYS_gettid)
15 #elif defined(__toaru__)
18 # define gettid() GetCurrentThreadId()
38 unsigned int started:1;
51 pthread_mutex_t mutex;
54 KRK_Function(current_thread) {
59 #define IS_Thread(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(Thread)))
60 #define AS_Thread(o) ((struct Thread *)AS_OBJECT(o))
61 #define CURRENT_CTYPE struct Thread *
62 #define CURRENT_NAME self
64 static volatile int _threadLock = 0;
65 static void * _startthread(
void * _threadObj) {
66 struct Thread *
self = _threadObj;
67 #if defined(__APPLE__) && defined(__aarch64__)
68 krk_forceThreadData();
73 vm.globalFlags |= KRK_GLOBAL_THREADS;
74 _obtain_lock(_threadLock);
75 if (
vm.threads->next) {
79 _release_lock(_threadLock);
98 _obtain_lock(_threadLock);
106 previous = previous->
next;
108 _release_lock(_threadLock);
118 return INTEGER_VAL(self->tid);
123 return krk_runtimeError(KRK_EXC(ThreadError),
"Thread can not join itself.");
125 return krk_runtimeError(KRK_EXC(ThreadError),
"Thread has not been started.");
127 pthread_join(self->nativeRef, NULL);
131 KRK_Method(
Thread,start) {
133 if (!
krk_parseArgs(
".|I", (
const char*[]){
"maxrec"}, &maxrec))
return NONE_VAL();
136 return krk_runtimeError(KRK_EXC(ThreadError),
"Thread has already been started.");
140 self->maxrec = maxrec;
141 pthread_create(&self->nativeRef, NULL, _startthread, (
void*)
self);
146 KRK_Method(
Thread,is_alive) {
148 return BOOLEAN_VAL(self->alive);
153 #define IS_Lock(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(Lock)))
154 #define AS_Lock(o) ((struct Lock *)AS_OBJECT(o))
155 #define CURRENT_CTYPE struct Lock *
157 KRK_Method(
Lock,__init__) {
159 pthread_mutex_init(&self->mutex, NULL);
163 static inline void _pushLockStatus(
struct Lock *
self,
struct StringBuilder * sb) {
166 if (self->mutex.__data.__owner) {
167 pushStringBuilderStr(sb,
" (locked)", 9);
169 pushStringBuilderStr(sb,
" (unlocked)", 11);
178 KRK_Method(
Lock,__repr__) {
181 pushStringBuilderStr(&sb,
"<Lock ", 6);
186 size_t len = snprintf(tmp, 100,
"%p", (
void*)
self);
187 pushStringBuilderStr(&sb, tmp, len);
190 _pushLockStatus(
self,&sb);
192 pushStringBuilder(&sb,
'>');
193 return finishStringBuilder(&sb);
196 KRK_Method(
Lock,__enter__) {
198 pthread_mutex_lock(&self->mutex);
202 KRK_Method(
Lock,__exit__) {
203 pthread_mutex_unlock(&self->mutex);
219 "@brief Methods and classes for creating platform threads.");
221 KRK_DOC(BIND_FUNC(threadsModule, current_thread),
222 "@brief Obtain a reference to the current thread.\n"
224 "Returns the @ref Thread object associated with the calling thread, if one exists.");
226 KrkClass * ThreadError =
krk_makeClass(threadsModule, &KRK_EXC(ThreadError),
"ThreadError",
vm.exceptions->OSError);
228 "Raised in various situations when an action on a thread is invalid."
234 "Base class for building threaded execution contexts.\n\n"
235 "The @ref Thread class should be subclassed and the subclass should implement a @c run method."
238 KRK_DOC(BIND_METHOD(
Thread,start),
"Start the thread. A thread may only be started once.");
239 KRK_DOC(BIND_METHOD(
Thread,join),
"Join the thread. Does not return until the thread finishes.");
240 KRK_DOC(BIND_METHOD(
Thread,is_alive),
"Query the status of the thread.");
241 KRK_DOC(BIND_PROP(
Thread,tid),
"The platform-specific thread identifier, if available. Usually an integer.");
246 "Represents an atomic mutex.\n\n"
247 "@ref Lock objects allow for exclusive access to a resource and can be used in a @c with block."
249 Lock->allocSize =
sizeof(
struct Lock);
250 KRK_DOC(BIND_METHOD(
Lock,__init__),
"Initialize a system mutex.");
251 KRK_DOC(BIND_METHOD(
Lock,__enter__),
"Acquire the lock.");
252 KRK_DOC(BIND_METHOD(
Lock,__exit__),
"Release the lock.");
253 BIND_METHOD(
Lock,__repr__);
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Top-level header with configuration macros.
Represents a managed call state in a VM thread.
KrkClass * krk_makeClass(KrkInstance *module, KrkClass **_class, const char *name, KrkClass *base)
Convenience function for creating new types.
KrkTable methods
General attributes table.
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
struct KrkClass * _class
Metaclass.
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
KrkTable fields
Attributes table.
The most basic object type.
int krk_tableGet(KrkTable *table, KrkValue key, KrkValue *value)
Obtain the value associated with a key in a table.
void krk_attachNamedObject(KrkTable *table, const char name[], KrkObj *obj)
Attach an object to an attribute table.
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
Execution state of a VM thread.
struct KrkThreadState * next
unsigned int maximumCallDepth
Stack reference or primative value.
Simple atomic structure for waiting.
Inline flexible string array.
Object representation of a system thread.
Convience header for providing atomic operations to threads.
Utilities for creating native bindings.
#define krk_parseArgs(f, n,...)
Parse arguments to a function while accepting keyword arguments.
#define KRK_DOC(thing, text)
Attach documentation to a thing of various types.
krk_threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
void krk_resetStack(void)
Reset the current thread's stack state to the top level.
void krk_module_init_threading(void)
Initialize the built-in 'threading' module.
KrkValue krk_callStack(int argCount)
Call a callable on the stack with argCount arguments.
#define vm
Convenience macro for namespacing.
void krk_push(KrkValue value)
Push a stack value.