Eliminate forced uses of GC pausing and fix up some more thread stuff; still need locks on collections
This commit is contained in:
parent
bd5619b32d
commit
345b021936
@ -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__",
|
||||
|
11
src/kuroko.c
11
src/kuroko.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
45
src/memory.c
45
src/memory.c
@ -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."));
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
55
src/vm.c
55
src/vm.c
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
6
src/vm.h
6
src/vm.h
@ -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);
|
||||
|
40
test/testRacingThreads.krk
Normal file
40
test/testRacingThreads.krk
Normal 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)
|
0
test/testRacingThreads.krk.expect
Normal file
0
test/testRacingThreads.krk.expect
Normal file
Loading…
Reference in New Issue
Block a user