|
@@ -1,7 +1,7 @@
|
|
|
/*
|
|
|
* thread.c
|
|
|
*
|
|
|
- * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
|
|
|
+ * Copyright (C) 2018 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
|
|
|
*
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
@@ -56,77 +56,57 @@ static dword_t alloc_tid()
|
|
|
return tid;
|
|
|
}
|
|
|
|
|
|
-static inline bool_t test_condition(wait_condition_t condition, dword_t *pointer, dword_t value)
|
|
|
+static inline bool_t test_condition(wait_condition_t *condition)
|
|
|
{
|
|
|
- bool_t satisfied;
|
|
|
+ wait_condition_t **ptr;
|
|
|
|
|
|
- switch (condition)
|
|
|
+ switch (condition->type)
|
|
|
{
|
|
|
- case WAIT_NEVER:
|
|
|
- satisfied = TRUE;
|
|
|
- break;
|
|
|
-
|
|
|
+ case WAIT_GROUP_ANY:
|
|
|
+ for (ptr = condition->conditions; *ptr; ptr++) if (test_condition(*ptr)) return TRUE;
|
|
|
+ return FALSE;
|
|
|
+ case WAIT_GROUP_ALL:
|
|
|
+ for (ptr = condition->conditions; *ptr; ptr++) if (!test_condition(*ptr)) return FALSE;
|
|
|
+ return TRUE;
|
|
|
case WAIT_ALWAYS:
|
|
|
- satisfied = FALSE;
|
|
|
- break;
|
|
|
-
|
|
|
+ return FALSE;
|
|
|
case WAIT_UNTIL_EQUAL:
|
|
|
- satisfied = (*pointer == value);
|
|
|
- break;
|
|
|
-
|
|
|
+ return *condition->pointer == condition->value;
|
|
|
case WAIT_UNTIL_NOT_EQUAL:
|
|
|
- satisfied = (*pointer != value);
|
|
|
- break;
|
|
|
-
|
|
|
+ return (*condition->pointer != condition->value);
|
|
|
case WAIT_UNTIL_LESS:
|
|
|
- satisfied = (*pointer < value);
|
|
|
- break;
|
|
|
-
|
|
|
+ return (*condition->pointer < condition->value);
|
|
|
case WAIT_UNTIL_NOT_LESS:
|
|
|
- satisfied = (*pointer >= value);
|
|
|
- break;
|
|
|
-
|
|
|
+ return (*condition->pointer >= condition->value);
|
|
|
case WAIT_UNTIL_GREATER:
|
|
|
- satisfied = (*pointer > value);
|
|
|
- break;
|
|
|
-
|
|
|
+ return (*condition->pointer > condition->value);
|
|
|
case WAIT_UNTIL_NOT_GREATER:
|
|
|
- satisfied = (*pointer <= value);
|
|
|
- break;
|
|
|
-
|
|
|
+ return (*condition->pointer <= condition->value);
|
|
|
default:
|
|
|
KERNEL_CRASH("Invalid wait condition value");
|
|
|
- break;
|
|
|
+ return FALSE;
|
|
|
}
|
|
|
-
|
|
|
- return satisfied;
|
|
|
}
|
|
|
|
|
|
static inline bool_t is_thread_ready(thread_t *thread)
|
|
|
{
|
|
|
qword_t current_time = syscall_get_milliseconds();
|
|
|
|
|
|
- if (thread->terminated) return FALSE;
|
|
|
- if (thread->frozen > 0 && !thread->syscall_lock) return FALSE;
|
|
|
+ if (thread->terminating || thread->terminated) return FALSE;
|
|
|
+ if (thread->frozen > 0 && !thread->in_kernel) return FALSE;
|
|
|
+ if (!thread->wait) return TRUE;
|
|
|
|
|
|
- if (test_condition(thread->wait_condition, thread->wait_pointer, thread->wait_value))
|
|
|
+ if (test_condition(thread->wait->root))
|
|
|
{
|
|
|
- thread->wait_condition = WAIT_NEVER;
|
|
|
- thread->wait_result = WAIT_CONDITION_HIT;
|
|
|
+ thread->wait->result = WAIT_CONDITION_HIT;
|
|
|
+ thread->wait = NULL;
|
|
|
return TRUE;
|
|
|
}
|
|
|
|
|
|
- if (thread->wait_timeout != 0ULL && (current_time - thread->wait_timestamp) >= (qword_t)thread->wait_timeout)
|
|
|
+ if (thread->wait->timeout != NO_TIMEOUT && (current_time - thread->wait->timestamp) >= (qword_t)thread->wait->timeout)
|
|
|
{
|
|
|
- thread->wait_condition = WAIT_NEVER;
|
|
|
- thread->wait_result = WAIT_TIMED_OUT;
|
|
|
- return TRUE;
|
|
|
- }
|
|
|
-
|
|
|
- if (thread->cancel_io)
|
|
|
- {
|
|
|
- thread->wait_condition = WAIT_NEVER;
|
|
|
- thread->wait_result = WAIT_CANCELED;
|
|
|
+ thread->wait->result = WAIT_TIMED_OUT;
|
|
|
+ thread->wait = NULL;
|
|
|
return TRUE;
|
|
|
}
|
|
|
|
|
@@ -187,14 +167,11 @@ dword_t create_thread_internal(process_t *proc, thread_state_t *initial_state, d
|
|
|
thread->running_ticks = 0ULL;
|
|
|
thread->owner_process = proc;
|
|
|
thread->exit_code = 0;
|
|
|
+ thread->terminating = FALSE;
|
|
|
thread->terminated = FALSE;
|
|
|
- thread->cancel_io = FALSE;
|
|
|
- thread->syscall_lock = 0;
|
|
|
- thread->wait_condition = WAIT_NEVER;
|
|
|
- thread->wait_timestamp = 0ULL;
|
|
|
- thread->wait_timeout = 0;
|
|
|
- thread->wait_pointer = NULL;
|
|
|
- thread->wait_value = 0;
|
|
|
+ thread->in_kernel = 0;
|
|
|
+ thread->last_context = NULL;
|
|
|
+ thread->wait = NULL;
|
|
|
memset(&thread->kernel_handler, 0, sizeof(thread->kernel_handler));
|
|
|
memset(&thread->user_handler, 0, sizeof(thread->user_handler));
|
|
|
|
|
@@ -353,39 +330,22 @@ found:
|
|
|
leave_critical(&critical);
|
|
|
}
|
|
|
|
|
|
-wait_result_t scheduler_wait(wait_condition_t condition, dword_t timeout, uintptr_t *pointer, uintptr_t value)
|
|
|
+wait_result_t scheduler_wait(wait_condition_t *condition, dword_t timeout)
|
|
|
{
|
|
|
- if (test_condition(condition, pointer, value)) return WAIT_CONDITION_HIT;
|
|
|
+ if (test_condition(condition)) return WAIT_CONDITION_HIT;
|
|
|
if (timeout == 0) return WAIT_TIMED_OUT;
|
|
|
|
|
|
- critical_t critical;
|
|
|
- enter_critical(&critical);
|
|
|
-
|
|
|
- if (timeout != NO_TIMEOUT)
|
|
|
- {
|
|
|
- current_thread->wait_timestamp = syscall_get_milliseconds();
|
|
|
- current_thread->wait_timeout = timeout;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- current_thread->wait_timestamp = 0ULL;
|
|
|
- current_thread->wait_timeout = 0;
|
|
|
- }
|
|
|
-
|
|
|
- current_thread->wait_pointer = pointer;
|
|
|
- current_thread->wait_value = value;
|
|
|
- current_thread->wait_condition = condition;
|
|
|
-
|
|
|
- leave_critical(&critical);
|
|
|
+ wait_t wait = { .root = condition, .timeout = timeout, .timestamp = syscall_get_milliseconds(), .result = WAIT_CANCELED };
|
|
|
+ while (!__sync_bool_compare_and_swap(¤t_thread->wait, NULL, &wait)) continue;
|
|
|
syscall_yield_quantum();
|
|
|
|
|
|
- return current_thread->wait_result;
|
|
|
+ return wait.result;
|
|
|
}
|
|
|
|
|
|
sysret_t syscall_sleep(qword_t milliseconds)
|
|
|
{
|
|
|
- scheduler_wait(WAIT_ALWAYS, milliseconds, NULL, 0);
|
|
|
- return ERR_SUCCESS;
|
|
|
+ wait_condition_t condition = { .type = WAIT_ALWAYS };
|
|
|
+ return scheduler_wait(&condition, milliseconds) == WAIT_CANCELED ? ERR_CANCELED : ERR_SUCCESS;
|
|
|
}
|
|
|
|
|
|
sysret_t syscall_yield_quantum()
|
|
@@ -528,9 +488,15 @@ found:
|
|
|
dword_t terminate_thread_internal(thread_t *thread, dword_t exit_code)
|
|
|
{
|
|
|
critical_t critical;
|
|
|
- thread->cancel_io = TRUE;
|
|
|
+ thread->terminating = TRUE;
|
|
|
+
|
|
|
+ if (thread != current_thread)
|
|
|
+ {
|
|
|
+ wait_condition_t cond = { .type = WAIT_UNTIL_EQUAL, .pointer = (dword_t*)&thread->in_kernel, .value = 0 };
|
|
|
+ wait_result_t result = scheduler_wait(&cond, NO_TIMEOUT);
|
|
|
+ if (result == WAIT_CANCELED) return ERR_CANCELED;
|
|
|
+ }
|
|
|
|
|
|
- if (thread != current_thread) acquire_lock(&thread->syscall_lock);
|
|
|
enter_critical(&critical);
|
|
|
|
|
|
thread->exit_code = exit_code;
|
|
@@ -610,7 +576,7 @@ sysret_t syscall_query_thread(handle_t handle, thread_info_t info_type, void *bu
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- ((thread_state_t*)safe_buffer)->regs = *thread->syscall_regs;
|
|
|
+ ((thread_state_t*)safe_buffer)->regs = *thread->last_context;
|
|
|
fpu_save(((thread_state_t*)safe_buffer)->fpu_state);
|
|
|
}
|
|
|
}
|
|
@@ -694,7 +660,7 @@ sysret_t syscall_set_thread(handle_t handle, thread_info_t info_type, const void
|
|
|
critical_t critical;
|
|
|
if (current_thread->tid != thread->tid) enter_critical(&critical);
|
|
|
|
|
|
- if (thread->syscall_lock == 0)
|
|
|
+ if (thread->in_kernel == 0)
|
|
|
{
|
|
|
thread->state.regs.eax = new_state->regs.eax;
|
|
|
thread->state.regs.ecx = new_state->regs.ecx;
|
|
@@ -707,21 +673,20 @@ sysret_t syscall_set_thread(handle_t handle, thread_info_t info_type, const void
|
|
|
thread->state.regs.eip = new_state->regs.eip;
|
|
|
thread->state.regs.eflags = (thread->state.regs.eflags & ~SAFE_EFLAGS_MASK) | (new_state->regs.eflags & SAFE_EFLAGS_MASK);
|
|
|
}
|
|
|
- else if (thread->syscall_regs != NULL)
|
|
|
+ else if (thread->last_context)
|
|
|
{
|
|
|
- thread->syscall_regs->eax = new_state->regs.eax;
|
|
|
- thread->syscall_regs->ecx = new_state->regs.ecx;
|
|
|
- thread->syscall_regs->edx = new_state->regs.edx;
|
|
|
- thread->syscall_regs->ebx = new_state->regs.ebx;
|
|
|
- thread->syscall_regs->esp = new_state->regs.esp;
|
|
|
- thread->syscall_regs->ebp = new_state->regs.ebp;
|
|
|
- thread->syscall_regs->esi = new_state->regs.esi;
|
|
|
- thread->syscall_regs->edi = new_state->regs.edi;
|
|
|
- thread->syscall_regs->eip = new_state->regs.eip;
|
|
|
- thread->syscall_regs->eflags = (thread->state.regs.eflags & ~SAFE_EFLAGS_MASK) | (new_state->regs.eflags & SAFE_EFLAGS_MASK);
|
|
|
+ thread->last_context->eax = new_state->regs.eax;
|
|
|
+ thread->last_context->ecx = new_state->regs.ecx;
|
|
|
+ thread->last_context->edx = new_state->regs.edx;
|
|
|
+ thread->last_context->ebx = new_state->regs.ebx;
|
|
|
+ thread->last_context->esp = new_state->regs.esp;
|
|
|
+ thread->last_context->ebp = new_state->regs.ebp;
|
|
|
+ thread->last_context->esi = new_state->regs.esi;
|
|
|
+ thread->last_context->edi = new_state->regs.edi;
|
|
|
+ thread->last_context->eip = new_state->regs.eip;
|
|
|
+ thread->last_context->eflags = (thread->last_context->eflags & ~SAFE_EFLAGS_MASK) | (new_state->regs.eflags & SAFE_EFLAGS_MASK);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
if (current_thread->tid != thread->tid)
|
|
|
{
|
|
|
memcpy(thread->state.fpu_state, new_state->fpu_state, sizeof(thread->state.fpu_state));
|
|
@@ -773,7 +738,8 @@ sysret_t syscall_wait_thread(handle_t handle, dword_t timeout)
|
|
|
if (!reference_by_handle(handle, OBJECT_THREAD, (object_t**)&thread)) return ERR_INVALID;
|
|
|
}
|
|
|
|
|
|
- ret = scheduler_wait(WAIT_UNTIL_NOT_EQUAL, timeout, &thread->terminated, FALSE);
|
|
|
+ wait_condition_t condition = { .type = WAIT_UNTIL_NOT_EQUAL, .pointer = &thread->terminated, .value = FALSE };
|
|
|
+ ret = scheduler_wait(&condition, timeout);
|
|
|
|
|
|
dereference(&thread->header);
|
|
|
return ret;
|
|
@@ -851,14 +817,11 @@ void thread_init(void)
|
|
|
main_thread->running_ticks = 0ULL;
|
|
|
main_thread->owner_process = kernel_process;
|
|
|
list_append(&kernel_process->threads, &main_thread->in_process_list);
|
|
|
- main_thread->syscall_lock = 0;
|
|
|
+ main_thread->in_kernel = 1;
|
|
|
+ main_thread->last_context = NULL;
|
|
|
main_thread->terminated = FALSE;
|
|
|
main_thread->previous_mode = KERNEL_MODE;
|
|
|
- main_thread->wait_condition = WAIT_NEVER;
|
|
|
- main_thread->wait_timestamp = 0ULL;
|
|
|
- main_thread->wait_timeout = 0;
|
|
|
- main_thread->wait_pointer = NULL;
|
|
|
- main_thread->wait_value = 0;
|
|
|
+ main_thread->wait = NULL;
|
|
|
|
|
|
memset(&main_thread->kernel_handler, 0, sizeof(main_thread->kernel_handler));
|
|
|
memset(&main_thread->user_handler, 0, sizeof(main_thread->user_handler));
|