diff --git a/src/obj_list.c b/src/obj_list.c index d45be1e..c337dcf 100644 --- a/src/obj_list.c +++ b/src/obj_list.c @@ -3,6 +3,7 @@ #include "value.h" #include "memory.h" #include "util.h" +#include "threads.h" #define LIST_WRAP_INDEX() \ if (index < 0) index += self->values.count; \ diff --git a/src/table.c b/src/table.c index cefc036..a06bcd6 100644 --- a/src/table.c +++ b/src/table.c @@ -6,6 +6,7 @@ #include "memory.h" #include "table.h" #include "vm.h" +#include "threads.h" #define TABLE_MAX_LOAD 0.75 @@ -13,6 +14,7 @@ void krk_initTable(KrkTable * table) { table->count = 0; table->capacity = 0; table->entries = NULL; + pthread_rwlock_init(&table->lock, NULL); } void krk_freeTable(KrkTable * table) { @@ -82,6 +84,7 @@ static void adjustCapacity(KrkTable * table, size_t capacity) { } int krk_tableSet(KrkTable * table, KrkValue key, KrkValue value) { + pthread_rwlock_wrlock(&table->lock); if (table->count + 1 > table->capacity * TABLE_MAX_LOAD) { size_t capacity = GROW_CAPACITY(table->capacity); adjustCapacity(table, capacity); @@ -91,6 +94,7 @@ int krk_tableSet(KrkTable * table, KrkValue key, KrkValue value) { if (isNewKey && IS_NONE(entry->value)) table->count++; entry->key = key; entry->value = value; + pthread_rwlock_unlock(&table->lock); return isNewKey; } @@ -105,32 +109,48 @@ void krk_tableAddAll(KrkTable * from, KrkTable * to) { int krk_tableGet(KrkTable * table, KrkValue key, KrkValue * value) { if (table->count == 0) return 0; + pthread_rwlock_rdlock(&table->lock); KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key); - if (entry->key.type == VAL_KWARGS) return 0; - *value = entry->value; - return 1; + if (entry->key.type == VAL_KWARGS) { + pthread_rwlock_unlock(&table->lock); + return 0; + } else { + *value = entry->value; + pthread_rwlock_unlock(&table->lock); + return 1; + } } int krk_tableDelete(KrkTable * table, KrkValue key) { if (table->count == 0) return 0; + pthread_rwlock_rdlock(&table->lock); KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key); - if (entry->key.type == VAL_KWARGS) return 0; + if (entry->key.type == VAL_KWARGS) { + pthread_rwlock_unlock(&table->lock); + return 0; + } entry->key = KWARGS_VAL(0); entry->value = BOOLEAN_VAL(1); + pthread_rwlock_unlock(&table->lock); return 1; } KrkString * krk_tableFindString(KrkTable * table, const char * chars, size_t length, uint32_t hash) { if (table->count == 0) return NULL; + pthread_rwlock_rdlock(&table->lock); uint32_t index = hash % table->capacity; for (;;) { KrkTableEntry * entry = &table->entries[index]; if (entry->key.type == VAL_KWARGS) { - if (IS_NONE(entry->value)) return NULL; + if (IS_NONE(entry->value)) { + pthread_rwlock_unlock(&table->lock); + return NULL; + } } else if (AS_STRING(entry->key)->length == length && AS_STRING(entry->key)->hash == hash && memcmp(AS_STRING(entry->key)->chars, chars, length) == 0) { + pthread_rwlock_unlock(&table->lock); return AS_STRING(entry->key); } index = (index + 1) % table->capacity; diff --git a/src/table.h b/src/table.h index 16de037..8c79826 100644 --- a/src/table.h +++ b/src/table.h @@ -10,6 +10,7 @@ #include #include "kuroko.h" #include "value.h" +#include "threads.h" typedef struct { KrkValue key; @@ -20,6 +21,7 @@ typedef struct { size_t count; size_t capacity; KrkTableEntry * entries; + pthread_rwlock_t lock; } KrkTable; extern void krk_initTable(KrkTable * table); diff --git a/src/threads.h b/src/threads.h new file mode 100644 index 0000000..cf857d0 --- /dev/null +++ b/src/threads.h @@ -0,0 +1,30 @@ +#pragma once + +#ifdef ENABLE_THREADING +#include +#include +static inline void _krk_internal_spin_lock(int volatile * lock) { + while(__sync_lock_test_and_set(lock, 0x01)) { + sched_yield(); + } +} + +static inline void _krk_internal_spin_unlock(int volatile * lock) { + __sync_lock_release(lock); +} + +#define _obtain_lock(v) _krk_internal_spin_lock(&v); +#define _release_lock(v) _krk_internal_spin_unlock(&v); + +#else + +#define _obtain_lock(v) +#define _release_lock(v) + +#define pthread_rwlock_init(a,b) +#define pthread_rwlock_wrlock(a) +#define pthread_rwlock_rdlock(a) +#define pthread_rwlock_unlock(a) + +#endif + diff --git a/src/vm.h b/src/vm.h index c80da54..2701867 100644 --- a/src/vm.h +++ b/src/vm.h @@ -234,27 +234,4 @@ extern int krk_doRecursiveModuleLoad(KrkString * name); extern KrkValue krk_operator_lt(KrkValue,KrkValue); extern KrkValue krk_operator_gt(KrkValue,KrkValue); -#ifdef ENABLE_THREADING -#include -static inline void _krk_internal_spin_lock(int volatile * lock) { - while(__sync_lock_test_and_set(lock, 0x01)) { - sched_yield(); - } -} - -static inline void _krk_internal_spin_unlock(int volatile * lock) { - __sync_lock_release(lock); -} - -#define _obtain_lock(v) _krk_internal_spin_lock(&v); -#define _release_lock(v) _krk_internal_spin_unlock(&v); -#else -#define _obtain_lock(v) -#define _release_lock(v) - -#define pthread_rwlock_init(a,b) -#define pthread_rwlock_wrlock(a) -#define pthread_rwlock_rdlock(a) -#define pthread_rwlock_unlock(a) -#endif diff --git a/test/testRacingThreads.krk b/test/testRacingThreads.krk index f0f3110..4293599 100644 --- a/test/testRacingThreads.krk +++ b/test/testRacingThreads.krk @@ -10,6 +10,7 @@ from fileio import open, stdin from threading import Thread let l = [] +let d = {} let stop = False class Racer(Thread): @@ -22,6 +23,7 @@ class Racer(Thread): l.append('test') else if l: l[choice % len(l)] += choice + d[choice] = str(choice) let racers = [Racer() for i in range(5)] @@ -38,3 +40,5 @@ for racer in racers: racer.join() print("Here's l:") print(l) +print("Here's d:") +print(d)