haiku/headers/private/kernel/thread.h

213 lines
5.8 KiB
C
Raw Normal View History

/*
* Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
* Distributed under the terms of the NewOS License.
*/
#ifndef _THREAD_H
#define _THREAD_H
#include <OS.h>
#include <thread_types.h>
#include <arch/thread.h>
* Introduced a set of functions (thread_prepare_to_block(), thread_block(), thread_unblock(),...) that allow a thread to wait for something without needing a semaphore or condition variable. It can simply block and another thread can unblock it. Supports timeouts and interrupting. Both semaphores and condition variables use this common mechanism, now. * Semaphores: - Some simplifications due to the thread blocking mechanism. - Changed locking order to sem -> thread. It was the other way around before and when introducing the wait_for_objects() support I had also introduced a situation where the locking was reverse, which could potentially cause a dead lock on SMP systems. - Instead of queueing thread structures, a semaphore queues queued_thread entries now, which are created on the stack. The thread::sem structure could thus be removed. - Added sem_entry::net_count, which is sem_entry::count plus the acquisition count of all waiting threads. This number is needed in remove_thread_from_sem() and instead of computing it there we maintain it. - Fixed remove_thread_from_sem(). It would not unblock threads, if the sem count was <= 0. - Made sem::last_acquirer unconditional. It is actually needed for sem_info::latest_holder. Fixed fill_sem_info() accordingly. - Added some optional tracing output, though only via ktrace_printf(). * Condition variables: - Could be simplified significantly through the use of the thread blocking mechanism. Removed a good deal of unnecessary code. - Moved the ConditionVariableEntry "flags" parameter from Wait() to Add(), and adjusted all places where condition variables are used accordingly. * snooze() uses thread_block_with_timeout() instead of a semaphore. * Simplified thread interrupting in the signal and user debugger code. Instead of separate functions for threads waiting on a semaphore or condititon variable, we only have a single thread_interrupt(), now. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25099 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-04-22 20:22:42 +04:00
// For the thread blocking inline functions only.
#include <kscheduler.h>
#include <ksignal.h>
struct kernel_args;
struct select_info;
struct thread_creation_attributes;
struct thread_creation_attributes {
int32 (*entry)(thread_func, void *);
const char* name;
int32 priority;
void* args1;
void* args2;
void* stack_address;
size_t stack_size;
// when calling kernel only
team_id team;
thread_id thread;
};
#ifdef __cplusplus
extern "C" {
#endif
void thread_enqueue(struct thread *t, struct thread_queue *q);
struct thread *thread_lookat_queue(struct thread_queue *q);
struct thread *thread_dequeue(struct thread_queue *q);
struct thread *thread_dequeue_id(struct thread_queue *q, thread_id id);
Merged branch haiku/branches/developer/bonefish/optimization revision 23139 into trunk, with roughly the following changes (for details svn log the branch): * The int 99 syscall handler is now fully in assembly. * Added a sysenter/sysexit handler and use it on Pentiums that support it (via commpage). * Got rid of i386_handle_trap(). A bit of functionality was moved into the assembly handler which now uses a jump table to call C functions handling the respective interrupt. * Some optimizations to get user debugger support code out of the interrupt handling path. * Introduced a thread::flags fields which allows to skip handling of rare events (signals, user debug enabling/disabling) on the common interrupt handling path. * Got rid of the explicit iframe stack. The iframes can still be retrieved by iterating through the stack frames. * Made the commpage an architecture independent feature. It's used for the real time data stuff (instead of creating a separate area). * The x86 CPU modules can now provide processor optimized versions for common functions (currently memcpy() only). They are used in the kernel and are provided to the userland via commpage entries. * Introduced build system feature allowing easy use of C structure member offsets in assembly code. Changes after merging: * Fixed merge conflict in src/system/kernel/arch/x86/arch_debug.cpp (caused by refactoring and introduction of "call" debugger command). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23370 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-01-11 03:36:44 +03:00
void thread_at_kernel_entry(bigtime_t now);
// called when the thread enters the kernel on behalf of the thread
void thread_at_kernel_exit(void);
Merged branch haiku/branches/developer/bonefish/optimization revision 23139 into trunk, with roughly the following changes (for details svn log the branch): * The int 99 syscall handler is now fully in assembly. * Added a sysenter/sysexit handler and use it on Pentiums that support it (via commpage). * Got rid of i386_handle_trap(). A bit of functionality was moved into the assembly handler which now uses a jump table to call C functions handling the respective interrupt. * Some optimizations to get user debugger support code out of the interrupt handling path. * Introduced a thread::flags fields which allows to skip handling of rare events (signals, user debug enabling/disabling) on the common interrupt handling path. * Got rid of the explicit iframe stack. The iframes can still be retrieved by iterating through the stack frames. * Made the commpage an architecture independent feature. It's used for the real time data stuff (instead of creating a separate area). * The x86 CPU modules can now provide processor optimized versions for common functions (currently memcpy() only). They are used in the kernel and are provided to the userland via commpage entries. * Introduced build system feature allowing easy use of C structure member offsets in assembly code. Changes after merging: * Fixed merge conflict in src/system/kernel/arch/x86/arch_debug.cpp (caused by refactoring and introduction of "call" debugger command). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23370 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-01-11 03:36:44 +03:00
void thread_at_kernel_exit_no_signals(void);
void thread_reset_for_exec(void);
status_t thread_init(struct kernel_args *args);
status_t thread_preboot_init_percpu(struct kernel_args *args, int32 cpuNum);
void thread_yield(bool force);
void thread_exit(void);
int32 thread_max_threads(void);
int32 thread_used_threads(void);
#define thread_get_current_thread arch_thread_get_current_thread
struct thread *thread_get_thread_struct(thread_id id);
struct thread *thread_get_thread_struct_locked(thread_id id);
static thread_id thread_get_current_thread_id(void);
static inline thread_id
thread_get_current_thread_id(void)
{
struct thread *thread = thread_get_current_thread();
return thread ? thread->id : 0;
}
static inline bool
thread_is_idle_thread(struct thread *thread)
{
return thread->entry == NULL;
}
thread_id allocate_thread_id(void);
thread_id peek_next_thread_id(void);
thread_id spawn_kernel_thread_etc(thread_func, const char *name, int32 priority,
void *args, team_id team, thread_id threadID);
status_t wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
status_t *_returnCode);
status_t select_thread(int32 object, struct select_info *info, bool kernel);
status_t deselect_thread(int32 object, struct select_info *info, bool kernel);
Merged branch haiku/branches/developer/bonefish/optimization revision 23139 into trunk, with roughly the following changes (for details svn log the branch): * The int 99 syscall handler is now fully in assembly. * Added a sysenter/sysexit handler and use it on Pentiums that support it (via commpage). * Got rid of i386_handle_trap(). A bit of functionality was moved into the assembly handler which now uses a jump table to call C functions handling the respective interrupt. * Some optimizations to get user debugger support code out of the interrupt handling path. * Introduced a thread::flags fields which allows to skip handling of rare events (signals, user debug enabling/disabling) on the common interrupt handling path. * Got rid of the explicit iframe stack. The iframes can still be retrieved by iterating through the stack frames. * Made the commpage an architecture independent feature. It's used for the real time data stuff (instead of creating a separate area). * The x86 CPU modules can now provide processor optimized versions for common functions (currently memcpy() only). They are used in the kernel and are provided to the userland via commpage entries. * Introduced build system feature allowing easy use of C structure member offsets in assembly code. Changes after merging: * Fixed merge conflict in src/system/kernel/arch/x86/arch_debug.cpp (caused by refactoring and introduction of "call" debugger command). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23370 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-01-11 03:36:44 +03:00
#define syscall_64_bit_return_value() arch_syscall_64_bit_return_value()
* Introduced a set of functions (thread_prepare_to_block(), thread_block(), thread_unblock(),...) that allow a thread to wait for something without needing a semaphore or condition variable. It can simply block and another thread can unblock it. Supports timeouts and interrupting. Both semaphores and condition variables use this common mechanism, now. * Semaphores: - Some simplifications due to the thread blocking mechanism. - Changed locking order to sem -> thread. It was the other way around before and when introducing the wait_for_objects() support I had also introduced a situation where the locking was reverse, which could potentially cause a dead lock on SMP systems. - Instead of queueing thread structures, a semaphore queues queued_thread entries now, which are created on the stack. The thread::sem structure could thus be removed. - Added sem_entry::net_count, which is sem_entry::count plus the acquisition count of all waiting threads. This number is needed in remove_thread_from_sem() and instead of computing it there we maintain it. - Fixed remove_thread_from_sem(). It would not unblock threads, if the sem count was <= 0. - Made sem::last_acquirer unconditional. It is actually needed for sem_info::latest_holder. Fixed fill_sem_info() accordingly. - Added some optional tracing output, though only via ktrace_printf(). * Condition variables: - Could be simplified significantly through the use of the thread blocking mechanism. Removed a good deal of unnecessary code. - Moved the ConditionVariableEntry "flags" parameter from Wait() to Add(), and adjusted all places where condition variables are used accordingly. * snooze() uses thread_block_with_timeout() instead of a semaphore. * Simplified thread interrupting in the signal and user debugger code. Instead of separate functions for threads waiting on a semaphore or condititon variable, we only have a single thread_interrupt(), now. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25099 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-04-22 20:22:42 +04:00
status_t thread_block();
status_t thread_block_with_timeout(uint32 timeoutFlags, bigtime_t timeout);
status_t thread_block_with_timeout_locked(uint32 timeoutFlags,
bigtime_t timeout);
bool thread_unblock(status_t threadID, status_t status);
// used in syscalls.c
status_t _user_set_thread_priority(thread_id thread, int32 newPriority);
status_t _user_rename_thread(thread_id thread, const char *name);
status_t _user_suspend_thread(thread_id thread);
status_t _user_resume_thread(thread_id thread);
status_t _user_rename_thread(thread_id thread, const char *name);
thread_id _user_spawn_thread(struct thread_creation_attributes* attributes);
status_t _user_wait_for_thread(thread_id id, status_t *_returnCode);
status_t _user_snooze_etc(bigtime_t timeout, int timebase, uint32 flags);
status_t _user_kill_thread(thread_id thread);
void _user_thread_yield(void);
void _user_exit_thread(status_t return_value);
bool _user_has_data(thread_id thread);
status_t _user_send_data(thread_id thread, int32 code, const void *buffer, size_t buffer_size);
status_t _user_receive_data(thread_id *_sender, void *buffer, size_t buffer_size);
thread_id _user_find_thread(const char *name);
status_t _user_get_thread_info(thread_id id, thread_info *info);
status_t _user_get_next_thread_info(team_id team, int32 *cookie, thread_info *info);
// ToDo: these don't belong here
struct rlimit;
int _user_getrlimit(int resource, struct rlimit * rlp);
int _user_setrlimit(int resource, const struct rlimit * rlp);
#ifdef __cplusplus
}
#endif
* Introduced a set of functions (thread_prepare_to_block(), thread_block(), thread_unblock(),...) that allow a thread to wait for something without needing a semaphore or condition variable. It can simply block and another thread can unblock it. Supports timeouts and interrupting. Both semaphores and condition variables use this common mechanism, now. * Semaphores: - Some simplifications due to the thread blocking mechanism. - Changed locking order to sem -> thread. It was the other way around before and when introducing the wait_for_objects() support I had also introduced a situation where the locking was reverse, which could potentially cause a dead lock on SMP systems. - Instead of queueing thread structures, a semaphore queues queued_thread entries now, which are created on the stack. The thread::sem structure could thus be removed. - Added sem_entry::net_count, which is sem_entry::count plus the acquisition count of all waiting threads. This number is needed in remove_thread_from_sem() and instead of computing it there we maintain it. - Fixed remove_thread_from_sem(). It would not unblock threads, if the sem count was <= 0. - Made sem::last_acquirer unconditional. It is actually needed for sem_info::latest_holder. Fixed fill_sem_info() accordingly. - Added some optional tracing output, though only via ktrace_printf(). * Condition variables: - Could be simplified significantly through the use of the thread blocking mechanism. Removed a good deal of unnecessary code. - Moved the ConditionVariableEntry "flags" parameter from Wait() to Add(), and adjusted all places where condition variables are used accordingly. * snooze() uses thread_block_with_timeout() instead of a semaphore. * Simplified thread interrupting in the signal and user debugger code. Instead of separate functions for threads waiting on a semaphore or condititon variable, we only have a single thread_interrupt(), now. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25099 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-04-22 20:22:42 +04:00
/*!
\a thread must be the current thread.
Thread lock can be, but doesn't need to be held.
*/
static inline bool
thread_is_interrupted(struct thread* thread, uint32 flags)
{
return ((flags & B_CAN_INTERRUPT)
&& (thread->sig_pending & ~thread->sig_block_mask) != 0)
|| ((flags & B_KILL_CAN_INTERRUPT)
&& (thread->sig_pending & KILL_SIGNALS));
}
static inline bool
thread_is_blocked(struct thread* thread)
{
return thread->wait.status == 1;
}
/*!
\a thread must be the current thread.
Thread lock can be, but doesn't need to be locked.
*/
static inline void
thread_prepare_to_block(struct thread* thread, uint32 flags, uint32 type,
const void* object)
* Introduced a set of functions (thread_prepare_to_block(), thread_block(), thread_unblock(),...) that allow a thread to wait for something without needing a semaphore or condition variable. It can simply block and another thread can unblock it. Supports timeouts and interrupting. Both semaphores and condition variables use this common mechanism, now. * Semaphores: - Some simplifications due to the thread blocking mechanism. - Changed locking order to sem -> thread. It was the other way around before and when introducing the wait_for_objects() support I had also introduced a situation where the locking was reverse, which could potentially cause a dead lock on SMP systems. - Instead of queueing thread structures, a semaphore queues queued_thread entries now, which are created on the stack. The thread::sem structure could thus be removed. - Added sem_entry::net_count, which is sem_entry::count plus the acquisition count of all waiting threads. This number is needed in remove_thread_from_sem() and instead of computing it there we maintain it. - Fixed remove_thread_from_sem(). It would not unblock threads, if the sem count was <= 0. - Made sem::last_acquirer unconditional. It is actually needed for sem_info::latest_holder. Fixed fill_sem_info() accordingly. - Added some optional tracing output, though only via ktrace_printf(). * Condition variables: - Could be simplified significantly through the use of the thread blocking mechanism. Removed a good deal of unnecessary code. - Moved the ConditionVariableEntry "flags" parameter from Wait() to Add(), and adjusted all places where condition variables are used accordingly. * snooze() uses thread_block_with_timeout() instead of a semaphore. * Simplified thread interrupting in the signal and user debugger code. Instead of separate functions for threads waiting on a semaphore or condititon variable, we only have a single thread_interrupt(), now. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25099 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-04-22 20:22:42 +04:00
{
thread->wait.flags = flags;
thread->wait.type = type;
thread->wait.object = object;
atomic_set(&thread->wait.status, 1);
// Set status last to guarantee that the other fields are initialized
// when a thread is waiting.
}
static inline status_t
thread_block_locked(struct thread* thread)
{
if (thread->wait.status == 1) {
// check for signals, if interruptable
if (thread_is_interrupted(thread, thread->wait.flags)) {
thread->wait.status = B_INTERRUPTED;
} else {
thread->next_state = B_THREAD_WAITING;
scheduler_reschedule();
}
}
return thread->wait.status;
}
static inline bool
thread_unblock_locked(struct thread* thread, status_t status)
{
if (atomic_test_and_set(&thread->wait.status, status, 1) != 1)
return false;
// wake up the thread, if it is sleeping
if (thread->state == B_THREAD_WAITING)
scheduler_enqueue_in_run_queue(thread);
return true;
}
static inline status_t
thread_interrupt(struct thread* thread, bool kill)
{
if ((thread->wait.flags & B_CAN_INTERRUPT) != 0
|| (kill && (thread->wait.flags & B_KILL_CAN_INTERRUPT) != 0)) {
thread_unblock_locked(thread, B_INTERRUPTED);
return B_OK;
}
return B_NOT_ALLOWED;
}
#endif /* _THREAD_H */