Kotlin machine scheduling primitives. (#1677)
This commit is contained in:
@@ -1103,6 +1103,17 @@ void DeinitMemory(MemoryState* memoryState) {
|
|||||||
::memoryState = nullptr;
|
::memoryState = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MemoryState* SuspendMemory() {
|
||||||
|
auto result = ::memoryState;
|
||||||
|
::memoryState = nullptr;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResumeMemory(MemoryState* state) {
|
||||||
|
RuntimeAssert(::memoryState == nullptr, "Cannot schedule on existing state");
|
||||||
|
::memoryState = state;
|
||||||
|
}
|
||||||
|
|
||||||
OBJ_GETTER(AllocInstance, const TypeInfo* type_info) {
|
OBJ_GETTER(AllocInstance, const TypeInfo* type_info) {
|
||||||
RuntimeAssert(type_info->instanceSize_ >= 0, "must be an object");
|
RuntimeAssert(type_info->instanceSize_ >= 0, "must be an object");
|
||||||
if (isArenaSlot(OBJ_RESULT)) {
|
if (isArenaSlot(OBJ_RESULT)) {
|
||||||
|
|||||||
@@ -379,6 +379,9 @@ struct MemoryState;
|
|||||||
MemoryState* InitMemory();
|
MemoryState* InitMemory();
|
||||||
void DeinitMemory(MemoryState*);
|
void DeinitMemory(MemoryState*);
|
||||||
|
|
||||||
|
MemoryState* SuspendMemory();
|
||||||
|
void ResumeMemory(MemoryState* state);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Object allocation.
|
// Object allocation.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
struct RuntimeState {
|
struct RuntimeState {
|
||||||
MemoryState* memoryState;
|
MemoryState* memoryState;
|
||||||
|
volatile int executionStatus;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*Initializer)(int initialize);
|
typedef void (*Initializer)(int initialize);
|
||||||
@@ -42,6 +43,24 @@ enum {
|
|||||||
DEINIT_GLOBALS = 2
|
DEINIT_GLOBALS = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SUSPENDED = 0,
|
||||||
|
RUNNING,
|
||||||
|
DESTROYING
|
||||||
|
};
|
||||||
|
|
||||||
|
bool updateStatusIf(RuntimeState* state, int oldStatus, int newStatus) {
|
||||||
|
#if KONAN_NO_THREADS
|
||||||
|
if (state->executionStatus == oldStatus) {
|
||||||
|
state->executionStatus = newStatus;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
return __sync_bool_compare_and_swap(&state->executionStatus, oldStatus, newStatus);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void InitOrDeinitGlobalVariables(int initialize) {
|
void InitOrDeinitGlobalVariables(int initialize) {
|
||||||
InitNode *currNode = initHeadNode;
|
InitNode *currNode = initHeadNode;
|
||||||
while (currNode != nullptr) {
|
while (currNode != nullptr) {
|
||||||
@@ -74,6 +93,7 @@ void deinitRuntime(RuntimeState* state) {
|
|||||||
DeinitMemory(state->memoryState);
|
DeinitMemory(state->memoryState);
|
||||||
konanDestructInstance(state);
|
konanDestructInstance(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -91,6 +111,7 @@ void AppendToInitializersTail(InitNode *next) {
|
|||||||
void Kotlin_initRuntimeIfNeeded() {
|
void Kotlin_initRuntimeIfNeeded() {
|
||||||
if (runtimeState == nullptr) {
|
if (runtimeState == nullptr) {
|
||||||
runtimeState = initRuntime();
|
runtimeState = initRuntime();
|
||||||
|
RuntimeCheck(updateStatusIf(runtimeState, SUSPENDED, RUNNING), "Cannot transition state to RUNNING for init");
|
||||||
// Register runtime deinit function at thread cleanup.
|
// Register runtime deinit function at thread cleanup.
|
||||||
konan::onThreadExit(Kotlin_deinitRuntimeIfNeeded);
|
konan::onThreadExit(Kotlin_deinitRuntimeIfNeeded);
|
||||||
}
|
}
|
||||||
@@ -98,9 +119,40 @@ void Kotlin_initRuntimeIfNeeded() {
|
|||||||
|
|
||||||
void Kotlin_deinitRuntimeIfNeeded() {
|
void Kotlin_deinitRuntimeIfNeeded() {
|
||||||
if (runtimeState != nullptr) {
|
if (runtimeState != nullptr) {
|
||||||
|
RuntimeCheck(updateStatusIf(runtimeState, RUNNING, DESTROYING), "Cannot transition state to DESTROYING");
|
||||||
deinitRuntime(runtimeState);
|
deinitRuntime(runtimeState);
|
||||||
runtimeState = nullptr;
|
runtimeState = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RuntimeState* Kotlin_createRuntime() {
|
||||||
|
return initRuntime();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kotlin_destroyRuntime(RuntimeState* state) {
|
||||||
|
RuntimeCheck(updateStatusIf(state, SUSPENDED, DESTROYING), "Cannot transition state to DESTROYING");
|
||||||
|
deinitRuntime(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeState* Kotlin_suspendRuntime() {
|
||||||
|
RuntimeCheck(::runtimeState != nullptr, "Runtime must be active on the current thread");
|
||||||
|
auto result = ::runtimeState;
|
||||||
|
RuntimeCheck(updateStatusIf(result, RUNNING, SUSPENDED), "Cannot transition state to SUSPENDED for suspend");
|
||||||
|
result->memoryState = SuspendMemory();
|
||||||
|
::runtimeState = nullptr;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kotlin_resumeRuntime(RuntimeState* state) {
|
||||||
|
RuntimeCheck(::runtimeState == nullptr, "Runtime must not be active on the current thread");
|
||||||
|
RuntimeCheck(updateStatusIf(state, SUSPENDED, RUNNING), "Cannot transition state to RUNNING for resume");
|
||||||
|
::runtimeState = state;
|
||||||
|
ResumeMemory(state->memoryState);
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeState* RUNTIME_USED Kotlin_getRuntime() {
|
||||||
|
RuntimeCheck(::runtimeState != nullptr, "Runtime must be active on the current thread");
|
||||||
|
return ::runtimeState;
|
||||||
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@@ -29,6 +29,22 @@ extern "C" {
|
|||||||
void RUNTIME_USED Kotlin_initRuntimeIfNeeded();
|
void RUNTIME_USED Kotlin_initRuntimeIfNeeded();
|
||||||
void RUNTIME_USED Kotlin_deinitRuntimeIfNeeded();
|
void RUNTIME_USED Kotlin_deinitRuntimeIfNeeded();
|
||||||
|
|
||||||
|
// Operations below allow flexible runtime scheduling on different threads.
|
||||||
|
// Created runtime is in SUSPENDED state, and need to be resumed for actual execution.
|
||||||
|
RuntimeState* RUNTIME_USED Kotlin_createRuntime();
|
||||||
|
// Runtime must be in SUSPENDED state, before it could be destroyed.
|
||||||
|
void RUNTIME_USED Kotlin_destroyRuntime(RuntimeState*);
|
||||||
|
|
||||||
|
// Transition current runtime from RUNNING to SUSPENDED state, and clearing thread local variable caching
|
||||||
|
// the runtime. After suspension, runtime could be rescheduled to a different thread.
|
||||||
|
RuntimeState* RUNTIME_USED Kotlin_suspendRuntime();
|
||||||
|
// Transition runtime from SUSPENDED to RUNNING state, and sets thread local variable caching
|
||||||
|
// the runtime. After resume, current thread could be used for executing Kotlin code.
|
||||||
|
void RUNTIME_USED Kotlin_resumeRuntime(RuntimeState*);
|
||||||
|
|
||||||
|
// Gets currently active runtime, nullptr if no runtime is currently available.
|
||||||
|
RuntimeState* RUNTIME_USED Kotlin_getRuntime();
|
||||||
|
|
||||||
// Appends given node to an initializer list.
|
// Appends given node to an initializer list.
|
||||||
void AppendToInitializersTail(struct InitNode*);
|
void AppendToInitializersTail(struct InitNode*);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user