Eliminate forced uses of GC pausing and fix up some more thread stuff; still need locks on collections

This commit is contained in:
K. Lange 2021-02-09 23:13:45 +09:00
parent bd5619b32d
commit 345b021936
10 changed files with 159 additions and 65 deletions

View File

@ -393,6 +393,8 @@ KRK_METHOD(LicenseReader,__call__,{
_noexport
void _createAndBind_builtins(void) {
vm.baseClasses->objectClass = krk_newClass(S("object"), NULL);
krk_push(OBJECT_VAL(vm.baseClasses->objectClass));
krk_defineNative(&vm.baseClasses->objectClass->methods, ":__class__", _type);
krk_defineNative(&vm.baseClasses->objectClass->methods, ".__dir__", krk_dirObject);
krk_defineNative(&vm.baseClasses->objectClass->methods, ".__str__", _strBase);
@ -401,6 +403,7 @@ void _createAndBind_builtins(void) {
vm.baseClasses->objectClass->docstring = S("Base class for all types.");
vm.baseClasses->moduleClass = krk_newClass(S("module"), vm.baseClasses->objectClass);
krk_push(OBJECT_VAL(vm.baseClasses->moduleClass));
krk_defineNative(&vm.baseClasses->moduleClass->methods, ".__repr__", _module_repr);
krk_defineNative(&vm.baseClasses->moduleClass->methods, ".__str__", _module_repr);
krk_finalizeClass(vm.baseClasses->moduleClass);
@ -409,6 +412,9 @@ void _createAndBind_builtins(void) {
vm.builtins = krk_newInstance(vm.baseClasses->moduleClass);
krk_attachNamedObject(&vm.modules, "__builtins__", (KrkObj*)vm.builtins);
krk_attachNamedObject(&vm.builtins->fields, "object", (KrkObj*)vm.baseClasses->objectClass);
krk_pop();
krk_pop();
krk_attachNamedObject(&vm.builtins->fields, "__name__", (KrkObj*)S("__builtins__"));
krk_attachNamedValue(&vm.builtins->fields, "__file__", NONE_VAL());
krk_attachNamedObject(&vm.builtins->fields, "__doc__",

View File

@ -148,10 +148,10 @@ static void tab_complete_func(rline_context_t * c) {
int matchCount = 0;
/* Take the last symbol name from the chain and get its member list from dir() */
KRK_PAUSE_GC();
for (;;) {
KrkValue dirList = krk_dirObject(1,(KrkValue[]){root});
krk_push(dirList);
if (!IS_INSTANCE(dirList)) {
fprintf(stderr,"\nInternal error while tab completting.\n");
goto _cleanup;
@ -159,13 +159,17 @@ static void tab_complete_func(rline_context_t * c) {
for (size_t i = 0; i < AS_LIST(dirList)->count; ++i) {
KrkString * s = AS_STRING(AS_LIST(dirList)->values[i]);
krk_push(OBJECT_VAL(s));
KrkToken asToken = {.start = s->chars, .literalWidth = s->length};
KrkValue thisValue = findFromProperty(root, asToken);
krk_push(thisValue);
if (IS_CLOSURE(thisValue) || IS_BOUND_METHOD(thisValue) ||
(IS_NATIVE(thisValue) && ((KrkNative*)AS_OBJECT(thisValue))->isMethod != 2)) {
char * tmp = malloc(s->length + 2);
sprintf(tmp, "%s(", s->chars);
s = krk_takeString(tmp, strlen(tmp));
krk_pop();
krk_push(OBJECT_VAL(s));
}
/* If this symbol is shorter than the current submatch, skip it. */
@ -198,10 +202,11 @@ static void tab_complete_func(rline_context_t * c) {
} else if (isGlobal && AS_OBJECT(root) == (KrkObj*)vm.builtins) {
extern char * syn_krk_keywords[];
KrkInstance * fakeKeywordsObject = krk_newInstance(vm.baseClasses->objectClass);
root = OBJECT_VAL(fakeKeywordsObject);
krk_push(root);
for (char ** keyword = syn_krk_keywords; *keyword; keyword++) {
krk_attachNamedValue(&fakeKeywordsObject->fields, *keyword, NONE_VAL());
}
root = OBJECT_VAL(fakeKeywordsObject);
continue;
} else {
break;
@ -262,7 +267,7 @@ _toomany:
_cleanup:
free(tmp);
free(space);
KRK_RESUME_GC();
krk_resetStack();
return;
}
}

View File

@ -207,12 +207,12 @@ static size_t sweep() {
KrkObj * object = vm.objects;
size_t count = 0;
while (object) {
if (object->isMarked || object->isProtected) {
if (object->isMarked || object->isImmortal) {
object->isMarked = 0;
object->isProtected = 0;
object->generation = 0;
previous = object;
object = object->next;
} else {
} else if (object->generation == 3) {
KrkObj * unreached = object;
object = object->next;
if (previous != NULL) {
@ -222,6 +222,10 @@ static size_t sweep() {
}
freeObject(unreached);
count++;
} else {
object->generation++;
previous = object;
object = object->next;
}
}
return count;
@ -254,6 +258,10 @@ static void markThreadRoots(KrkThreadState * thread) {
krk_markValue(thread->currentException);
if (thread->module) krk_markObject((KrkObj*)thread->module);
for (int i = 0; i < THREAD_SCRATCH_SIZE; ++i) {
krk_markValue(thread->scratchSpace[i]);
}
}
static void markRoots() {
@ -290,6 +298,34 @@ static KrkValue krk_collectGarbage_wrapper(int argc, KrkValue argv[]) {
return INTEGER_VAL(krk_collectGarbage());
}
static KrkValue krk_generations(int argc, KrkValue argv[]) {
#define MAX_GEN 4
krk_integer_type generations[MAX_GEN] = {0,0,0,0};
KrkObj * object = vm.objects;
while (object) {
generations[object->generation]++;
object = object->next;
}
/* Create a four-tuple */
KrkTuple * outTuple = krk_newTuple(MAX_GEN);
for (int i = 0; i < MAX_GEN; ++i) {
outTuple->values.values[i] = INTEGER_VAL(generations[i]);
}
outTuple->values.count = MAX_GEN;
return OBJECT_VAL(outTuple);
}
static KrkValue _gc_pause(int argc, KrkValue argv[]) {
vm.globalFlags |= (KRK_GC_PAUSED);
return NONE_VAL();
}
static KrkValue _gc_resume(int argc, KrkValue argv[]) {
vm.globalFlags &= ~(KRK_GC_PAUSED);
return NONE_VAL();
}
_noexport
void _createAndBind_gcMod(void) {
/**
@ -302,6 +338,9 @@ void _createAndBind_gcMod(void) {
krk_attachNamedObject(&gcModule->fields, "__name__", (KrkObj*)S("gc"));
krk_attachNamedValue(&gcModule->fields, "__file__", NONE_VAL());
krk_defineNative(&gcModule->fields, "collect", krk_collectGarbage_wrapper);
krk_defineNative(&gcModule->fields, "generations", krk_generations);
krk_defineNative(&gcModule->fields, "pause", _gc_pause);
krk_defineNative(&gcModule->fields, "resume", _gc_resume);
krk_attachNamedObject(&gcModule->fields, "__doc__",
(KrkObj*)S("Namespace containing methods for controlling the garbge collector."));
}

View File

@ -23,27 +23,29 @@ extern char ** environ;
KrkClass * OSError = NULL;
#define DO_KEY(key) krk_attachNamedObject(AS_DICT(result), #key, (KrkObj*)krk_copyString(buf. key, strlen(buf .key)))
#define S_KEY(key,val) krk_attachNamedObject(AS_DICT(result), #key, (KrkObj*)val);
#ifndef _WIN32
KRK_FUNC(uname,{
struct utsname buf;
if (uname(&buf) < 0) return NONE_VAL();
KRK_PAUSE_GC();
KrkValue result = krk_dict_of(0, NULL);
krk_push(result);
KrkValue result = krk_dict_of(5 * 2, (KrkValue[]) {
OBJECT_VAL(S("sysname")), OBJECT_VAL(krk_copyString(buf.sysname,strlen(buf.sysname))),
OBJECT_VAL(S("nodename")), OBJECT_VAL(krk_copyString(buf.nodename,strlen(buf.nodename))),
OBJECT_VAL(S("release")), OBJECT_VAL(krk_copyString(buf.release,strlen(buf.release))),
OBJECT_VAL(S("version")), OBJECT_VAL(krk_copyString(buf.version,strlen(buf.version))),
OBJECT_VAL(S("machine")), OBJECT_VAL(krk_copyString(buf.machine,strlen(buf.machine)))
});
DO_KEY(sysname);
DO_KEY(nodename);
DO_KEY(release);
DO_KEY(version);
DO_KEY(machine);
KRK_RESUME_GC();
return result;
return krk_pop();;
})
#else
KRK_FUNC(uname,{
KRK_PAUSE_GC();
KrkValue result = krk_dict_of(0, NULL);
krk_push(result);
TCHAR buffer[256] = TEXT("");
DWORD dwSize = sizeof(buffer);
@ -52,44 +54,37 @@ KRK_FUNC(uname,{
OSVERSIONINFOA versionInfo = {0};
versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionExA(&versionInfo);
KrkValue release;
if (versionInfo.dwMajorVersion == 10) {
release = OBJECT_VAL(S("10"));
S_KEY(release,S("10"));
} else if (versionInfo.dwMajorVersion == 6) {
if (versionInfo.dwMinorVersion == 3) {
release = OBJECT_VAL(S("8.1"));
S_KEY(release,S("8.1"));
} else if (versionInfo.dwMinorVersion == 2) {
release = OBJECT_VAL(S("8.0"));
S_KEY(release,S("8.0"));
} else if (versionInfo.dwMinorVersion == 1) {
release = OBJECT_VAL(S("7"));
S_KEY(release,S("7"));
} else if (versionInfo.dwMinorVersion == 0) {
release = OBJECT_VAL(S("Vista"));
S_KEY(release,S("Vista"));
}
} else {
release = OBJECT_VAL(S("XP or earlier"));
S_KEY(release,S("XP or earlier"));
}
char tmp[256];
sprintf(tmp, "%ld", versionInfo.dwBuildNumber);
KrkValue version = OBJECT_VAL(krk_copyString(tmp,strlen(tmp)));
KrkValue machine;
S_KEY(version, krk_copyString(tmp,strlen(tmp)));
if (sizeof(void *) == 8) {
machine = OBJECT_VAL(S("x64"));
S_KEY(machine,S("x64"));
} else {
machine = OBJECT_VAL(S("x86"));
S_KEY(machine,S("x86"));
}
KrkValue result = krk_dict_of(5 * 2, (KrkValue[]) {
OBJECT_VAL(S("sysname")), OBJECT_VAL(S("Windows")),
OBJECT_VAL(S("nodename")), OBJECT_VAL(krk_copyString(buffer,dwSize)),
OBJECT_VAL(S("release")), release,
OBJECT_VAL(S("version")), version,
OBJECT_VAL(S("machine")), machine
});
S_KEY(sysname,S("Windows"));
S_KEY(nodename,krk_copyString(buffer,dwSize));
KRK_RESUME_GC();
return result;
return krk_pop();
})
#endif

View File

@ -16,6 +16,7 @@ static KrkObj * allocateObject(size_t size, ObjType type) {
memset(object,0,size);
object->type = type;
object->next = vm.objects;
krk_currentThread.scratchSpace[2] = OBJECT_VAL(object);
vm.objects = object;
return object;
}

View File

@ -49,7 +49,8 @@ struct Obj {
ObjType type;
unsigned char isMarked:1;
unsigned char inRepr:1;
unsigned char isProtected:1;
unsigned char generation:2;
unsigned char isImmortal:1;
struct Obj * next;
};

View File

@ -623,19 +623,25 @@ static int call(KrkClosure * closure, int argCount, int extra) {
size_t totalArguments = closure->function->requiredArgs + closure->function->keywordArgs + closure->function->collectsArguments + closure->function->collectsKeywords;
size_t offsetOfExtraArgs = closure->function->requiredArgs + closure->function->keywordArgs;
size_t argCountX = argCount;
KrkValueArray positionals;
KrkTable keywords;
KrkValueArray * positionals;
KrkTable * keywords;
if (argCount && IS_KWARGS(krk_currentThread.stackTop[-1])) {
KRK_PAUSE_GC();
KrkValue myList = krk_list_of(0,NULL);
krk_currentThread.scratchSpace[0] = myList;
KrkValue myDict = krk_dict_of(0,NULL);
krk_currentThread.scratchSpace[1] = myDict;
positionals = AS_LIST(myList);
keywords = AS_DICT(myDict);
/* This processes the existing argument list into a ValueArray and a Table with the args and keywords */
if (!krk_processComplexArguments(argCount, &positionals, &keywords)) goto _errorDuringPositionals;
if (!krk_processComplexArguments(argCount, positionals, keywords)) goto _errorDuringPositionals;
argCount--; /* It popped the KWARGS value from the top, so we have one less argument */
/* Do we already know we have too many arguments? Let's bail before doing a bunch of work. */
if ((positionals.count > potentialPositionalArgs) && (!closure->function->collectsArguments)) {
checkArgumentCount(closure,positionals.count);
if ((positionals->count > potentialPositionalArgs) && (!closure->function->collectsArguments)) {
checkArgumentCount(closure,positionals->count);
goto _errorDuringPositionals;
}
@ -657,22 +663,23 @@ static int call(KrkClosure * closure, int argCount, int extra) {
}
/* Place positional arguments */
for (size_t i = 0; i < potentialPositionalArgs && i < positionals.count; ++i) {
krk_currentThread.stackTop[-argCount + i] = positionals.values[i];
for (size_t i = 0; i < potentialPositionalArgs && i < positionals->count; ++i) {
krk_currentThread.stackTop[-argCount + i] = positionals->values[i];
}
if (closure->function->collectsArguments) {
size_t count = (positionals.count > potentialPositionalArgs) ? (positionals.count - potentialPositionalArgs) : 0;
KrkValue * offset = (count == 0) ? NULL : &positionals.values[potentialPositionalArgs];
size_t count = (positionals->count > potentialPositionalArgs) ? (positionals->count - potentialPositionalArgs) : 0;
KrkValue * offset = (count == 0) ? NULL : &positionals->values[potentialPositionalArgs];
krk_push(krk_list_of(count, offset));
argCount++;
}
krk_freeValueArray(&positionals);
krk_freeValueArray(positionals);
krk_currentThread.scratchSpace[0] = NONE_VAL();
/* Now place keyword arguments */
for (size_t i = 0; i < keywords.capacity; ++i) {
KrkTableEntry * entry = &keywords.entries[i];
for (size_t i = 0; i < keywords->capacity; ++i) {
KrkTableEntry * entry = &keywords->entries[i];
if (entry->key.type != VAL_KWARGS) {
KrkValue name = entry->key;
KrkValue value = entry->value;
@ -716,10 +723,11 @@ _finishKwarg:
if (closure->function->collectsKeywords) {
krk_push(krk_dict_of(0,NULL));
argCount++;
krk_tableAddAll(&keywords, AS_DICT(krk_peek(0)));
krk_tableAddAll(keywords, AS_DICT(krk_peek(0)));
}
krk_freeTable(&keywords);
krk_freeTable(keywords);
krk_currentThread.scratchSpace[1] = NONE_VAL();
for (size_t i = 0; i < (size_t)closure->function->requiredArgs; ++i) {
if (IS_KWARGS(krk_currentThread.stackTop[-argCount + i])) {
@ -730,7 +738,6 @@ _finishKwarg:
}
}
KRK_RESUME_GC();
argCountX = argCount - (closure->function->collectsArguments + closure->function->collectsKeywords);
} else {
/* We can't have had any kwargs. */
@ -763,11 +770,12 @@ _finishKwarg:
return 1;
_errorDuringPositionals:
krk_freeValueArray(&positionals);
krk_freeValueArray(positionals);
krk_currentThread.scratchSpace[0] = NONE_VAL();
_errorAfterPositionals:
krk_freeTable(&keywords);
krk_freeTable(keywords);
krk_currentThread.scratchSpace[1] = NONE_VAL();
_errorAfterKeywords:
KRK_RESUME_GC();
return 0;
}
@ -798,18 +806,19 @@ int krk_callValue(KrkValue callee, int argCount, int extra) {
case OBJ_NATIVE: {
NativeFnKw native = (NativeFnKw)AS_NATIVE(callee)->function;
if (argCount && IS_KWARGS(krk_currentThread.stackTop[-1])) {
KRK_PAUSE_GC();
KrkValue myList = krk_list_of(0,NULL);
krk_currentThread.scratchSpace[0] = myList;
KrkValue myDict = krk_dict_of(0,NULL);
krk_currentThread.scratchSpace[1] = myDict;
if (!krk_processComplexArguments(argCount, AS_LIST(myList), AS_DICT(myDict))) {
KRK_RESUME_GC();
return 0;
}
KRK_RESUME_GC();
argCount--; /* Because that popped the kwargs value */
krk_currentThread.stackTop -= argCount + extra; /* We can just put the stack back to normal */
krk_push(myList);
krk_push(myDict);
krk_currentThread.scratchSpace[0] = NONE_VAL();
krk_currentThread.scratchSpace[1] = NONE_VAL();
krk_writeValueArray(AS_LIST(myList), myDict);
KrkValue result = native(AS_LIST(myList)->count-1, AS_LIST(myList)->values, 1);
if (krk_currentThread.stackTop == krk_currentThread.stack) return 0;
@ -1073,7 +1082,6 @@ static KrkValue krk_setclean(int argc, KrkValue argv[]) {
void krk_initVM(int flags) {
vm.globalFlags = flags & 0xFF00;
KRK_PAUSE_GC();
/* Reset current thread */
krk_resetStack();
@ -1208,7 +1216,6 @@ void krk_initVM(int flags) {
/* The VM is now ready to start executing code. */
krk_resetStack();
KRK_RESUME_GC();
}
/**

View File

@ -118,6 +118,9 @@ typedef struct ThreadState {
KrkValue currentException;
int flags;
long watchdog;
#define THREAD_SCRATCH_SIZE 16
KrkValue scratchSpace[THREAD_SCRATCH_SIZE];
} KrkThreadState;
typedef struct {
@ -180,9 +183,6 @@ extern void krk_attachNamedValue(KrkTable * table, const char name[], KrkValue o
extern KrkValue krk_runtimeError(KrkClass * type, const char * fmt, ...);
extern KrkThreadState * krk_getCurrentThread(void);
#define KRK_PAUSE_GC() do { vm.globalFlags |= KRK_GC_PAUSED; } while (0)
#define KRK_RESUME_GC() do { vm.globalFlags &= ~(KRK_GC_PAUSED); } while (0)
extern KrkInstance * krk_dictCreate(void);
extern KrkValue krk_runNext(void);
extern KrkClass * krk_getType(KrkValue);

View File

@ -0,0 +1,40 @@
####
# Demonstration of how container access is currently broken
# by threads and needs reader/writer locks.
####
import os
if 'KUROKO_TEST_ENV' in os.environ:
return 0
from fileio import open, stdin
from threading import Thread
let l = []
let stop = False
class Racer(Thread):
def run(self):
let myRando = open('/dev/urandom','rb')
while not stop:
let choice = myRando.read(1)[0]
if choice > 127:
l.append('test')
else if l:
l[choice % len(l)] += choice
let racerA = Racer()
let racerB = Racer()
racerA.start()
racerB.start()
print("Press enter to stop.")
stdin.readline()
stop = True
print("Waiting for threads...")
racerA.join()
racerB.join()
print("Here's l:")
print(l)

View File