Kotlin machine scheduling primitives. (#1677)
This commit is contained in:
@@ -1103,6 +1103,17 @@ void DeinitMemory(MemoryState* memoryState) {
|
||||
::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) {
|
||||
RuntimeAssert(type_info->instanceSize_ >= 0, "must be an object");
|
||||
if (isArenaSlot(OBJ_RESULT)) {
|
||||
|
||||
@@ -379,6 +379,9 @@ struct MemoryState;
|
||||
MemoryState* InitMemory();
|
||||
void DeinitMemory(MemoryState*);
|
||||
|
||||
MemoryState* SuspendMemory();
|
||||
void ResumeMemory(MemoryState* state);
|
||||
|
||||
//
|
||||
// Object allocation.
|
||||
//
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
struct RuntimeState {
|
||||
MemoryState* memoryState;
|
||||
volatile int executionStatus;
|
||||
};
|
||||
|
||||
typedef void (*Initializer)(int initialize);
|
||||
@@ -42,6 +43,24 @@ enum {
|
||||
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) {
|
||||
InitNode *currNode = initHeadNode;
|
||||
while (currNode != nullptr) {
|
||||
@@ -74,6 +93,7 @@ void deinitRuntime(RuntimeState* state) {
|
||||
DeinitMemory(state->memoryState);
|
||||
konanDestructInstance(state);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
@@ -91,6 +111,7 @@ void AppendToInitializersTail(InitNode *next) {
|
||||
void Kotlin_initRuntimeIfNeeded() {
|
||||
if (runtimeState == nullptr) {
|
||||
runtimeState = initRuntime();
|
||||
RuntimeCheck(updateStatusIf(runtimeState, SUSPENDED, RUNNING), "Cannot transition state to RUNNING for init");
|
||||
// Register runtime deinit function at thread cleanup.
|
||||
konan::onThreadExit(Kotlin_deinitRuntimeIfNeeded);
|
||||
}
|
||||
@@ -98,9 +119,40 @@ void Kotlin_initRuntimeIfNeeded() {
|
||||
|
||||
void Kotlin_deinitRuntimeIfNeeded() {
|
||||
if (runtimeState != nullptr) {
|
||||
RuntimeCheck(updateStatusIf(runtimeState, RUNNING, DESTROYING), "Cannot transition state to DESTROYING");
|
||||
deinitRuntime(runtimeState);
|
||||
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"
|
||||
|
||||
@@ -29,6 +29,22 @@ extern "C" {
|
||||
void RUNTIME_USED Kotlin_initRuntimeIfNeeded();
|
||||
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.
|
||||
void AppendToInitializersTail(struct InitNode*);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user