/*
* @OSF_FREE_FREE_COPYRIGHT@
*
*/
/*
* HISTORY
* $Log: uniproc.c,v $
* Revision 1.1.2.1 1996/09/09 17:19:13 barbou
* Adapted the "active_on_cthread" checks: the osfmach3_mach_thread struct
* can be used by tasks other than the init_task...
* [96/09/06 barbou]
*
* Adapted for clone().
* [1996/09/05 17:27:00 barbou]
*
* Created.
* [1996/09/02 12:46:07 barbou]
*
* $EndLog$
*/
#include <linux/autoconf.h>
#include <osfmach3/uniproc.h>
#include <osfmach3/assert.h>
#include <osfmach3/server_thread.h>
#include <linux/sched.h>
#define UNIPROC_PREEMPTION 0
#if UNIPROC_PREEMPTION
int uniproc_allow_preemption = FALSE;
#endif /* UNIPROC_PREEMPTION */
struct mutex uniproc_mutex = MUTEX_INITIALIZER;
cthread_t uniproc_holder_cthread = NULL;
#if UNIPROC_PREEMPTION
struct mutex uniproc_preemption_mutex = MUTEX_INITIALIZER;
#endif /* UNIPROC_PREEMPTION */
#if CONFIG_OSFMACH3_DEBUG
struct task_struct *uniproc_holder = NULL;
unsigned long uniproc_preemptibles = 0; /* #times became preemptible */
unsigned long uniproc_preemptions = 0; /* #times preemption occured */
#if defined(__STDC__)
#define UNIPROC_ASSERT(ex) \
MACRO_BEGIN \
if (!(ex)) { \
printk("Assertion failed: file: \"%s\", line: %d test: %s\n", \
__FILE__, __LINE__, # ex ); \
Debugger("assertion failure"); \
} \
MACRO_END
#else /* __STDC__ */
#define UNIPROC_ASSERT(ex) \
MACRO_BEGIN \
if (!(ex)) { \
printk("Assertion failed: file: \"%s\", line: %d test: %s\n", \
__FILE__, __LINE__, "ex"); \
Debugger("assertion failure"); \
} \
MACRO_END
#endif /* __STDC__ */
struct task_struct *
get_current_task(void)
{
struct server_thread_priv_data *priv_datap;
struct task_struct *current_task;
priv_datap = server_thread_get_priv_data(cthread_self());
current_task = priv_datap->current_task;
if (current_task->osfmach3.thread != init_task.osfmach3.thread) {
ASSERT(current_task->osfmach3.thread->active_on_cthread
== cthread_self());
}
return current_task;
}
void
set_current_task(
struct task_struct *current_task)
{
struct server_thread_priv_data *priv_datap;
struct task_struct *old_current_task;
priv_datap = server_thread_get_priv_data(cthread_self());
old_current_task = priv_datap->current_task;
if (old_current_task->osfmach3.thread != init_task.osfmach3.thread) {
ASSERT(old_current_task->osfmach3.thread->active_on_cthread
== cthread_self());
old_current_task->osfmach3.thread->active_on_cthread =
CTHREAD_NULL;
}
ASSERT(current_task->osfmach3.thread->active_on_cthread == CTHREAD_NULL);
if (current_task->osfmach3.thread != init_task.osfmach3.thread) {
current_task->osfmach3.thread->active_on_cthread = cthread_self();
}
priv_datap->current_task = current_task;
}
void
uniproc_has_entered(void)
{
UNIPROC_ASSERT(uniproc_holder == NULL);
UNIPROC_ASSERT(uniproc_holder_cthread == NULL);
current_set[smp_processor_id()] = get_current_task();
#if CONFIG_OSFMACH3_DEBUG
uniproc_holder = current;
#endif /* CONFIG_OSFMACH3_DEBUG */
uniproc_holder_cthread = cthread_self();
}
void
uniproc_enter(void)
{
#if UNIPROC_PREEMPTION
struct server_thread_priv_data *priv_datap;
#endif /* UNIPROC_PREEMPTION */
#if UNIPROC_PREEMPTION
if (!mutex_try_lock(&uniproc_mutex)) {
priv_datap = server_thread_get_priv_data(cthread_self());
if (priv_datap->preemptive && uniproc_allow_preemption) {
/* prioritary thread: try to preempt */
while (!uniproc_try_enter() &&
!uniproc_preempt()) {
server_thread_yield(1); /* yield for 1 ms */
}
/* we're all set */
return;
} else {
/* just block and wait for our turn */
mutex_lock(&uniproc_mutex);
}
}
#else /* UNIPROC_PREEMPTION */
mutex_lock(&uniproc_mutex);
#endif /* UNIPROC_PREEMPTION */
uniproc_has_entered();
}
boolean_t
uniproc_try_enter(void)
{
if (mutex_try_lock(&uniproc_mutex)) {
uniproc_has_entered();
return TRUE;
}
return FALSE;
}
void
uniproc_will_exit(void)
{
UNIPROC_ASSERT(uniproc_holder == current);
UNIPROC_ASSERT(uniproc_holder_cthread == cthread_self());
set_current_task(current);
current_set[smp_processor_id()] = (struct task_struct *) NULL;
#if CONFIG_OSFMACH3_DEBUG
uniproc_holder = NULL;
#endif /* CONFIG_OSFMACH3_DEBUG */
uniproc_holder_cthread = NULL;
}
void
uniproc_exit(void)
{
uniproc_will_exit();
mutex_unlock(&uniproc_mutex);
}
static __inline__ void
uniproc_change_current(
struct task_struct *old_task,
struct task_struct *new_task)
{
UNIPROC_ASSERT(uniproc_holder != NULL);
UNIPROC_ASSERT(uniproc_holder == old_task);
ASSERT(current == old_task);
current_set[smp_processor_id()] = new_task;
set_current_task(current);
#if CONFIG_OSFMACH3_DEBUG
uniproc_holder = current;
#endif /* CONFIG_OSFMACH3_DEBUG */
uniproc_holder_cthread = cthread_self();
}
void
uniproc_switch_to(
struct task_struct *old_task,
struct task_struct *new_task)
{
UNIPROC_ASSERT(uniproc_holder_cthread == cthread_self());
ASSERT(old_task == FIRST_TASK || new_task == FIRST_TASK);
uniproc_change_current(old_task, new_task);
}
#if UNIPROC_PREEMPTION
boolean_t
uniproc_preempt(void)
{
if (mutex_try_lock(&uniproc_preemption_mutex)) {
uniproc_change_current(current, get_current_task());
#if CONFIG_OSFMACH3_DEBUG
{
struct server_thread_priv_data *priv_datap;
priv_datap =
server_thread_get_priv_data(cthread_self());
if (priv_datap->preemptive) {
/*
* We actually preempted another thread...
* account for this glorious deed !
*/
uniproc_preemptions++;
} else {
/*
* It's just the preemptible thread
* preempting itself
*/
}
}
#endif /* CONFIG_OSFMACH3_DEBUG */
return TRUE;
}
return FALSE;
}
#endif /* UNIPROC_PREEMPTION */
void
uniproc_preemptible(void)
{
#if UNIPROC_PREEMPTION
if (uniproc_allow_preemption) {
UNIPROC_ASSERT(uniproc_holder == current);
UNIPROC_ASSERT(uniproc_holder_cthread == cthread_self());
#if CONFIG_OSFMACH3_DEBUG
uniproc_preemptibles++;
#endif /* CONFIG_OSFMACH3_DEBUG */
mutex_unlock(&uniproc_preemption_mutex);
} else {
uniproc_exit();
}
#else /* UNIPROC_PREEMPTION */
uniproc_exit();
#endif /* UNIPROC_PREEMPTION */
}
void
uniproc_unpreemptible(void)
{
#if UNIPROC_PREEMPTION
if (uniproc_allow_preemption && uniproc_preempt()) {
/*
* Nobody preempted us or we preempted someone else.
* Anyway, the uniproc is held now, so all is fine...
*/
} else {
/*
* We got preempted and we can't get back on stage
* right now...
*/
uniproc_enter();
}
#else /* UNIPROC_PREEMPTION */
uniproc_enter();
#endif /* UNIPROC_PREEMPTION */
}
#else /* CONFIG_OSFMACH3_DEBUG */
#define UNIPROC_ASSERT(ex)
#endif /* CONFIG_OSFMACH3_DEBUG */
void
uniproc_preemption_init(void)
{
#if UNIPROC_PREEMPTION
mutex_lock(&uniproc_preemption_mutex);
#endif /* UNIPROC_PREEMPTION */
}
boolean_t
holding_uniproc(void)
{
#ifdef CONFIG_OSFMACH3_DEBUG
if (uniproc_holder_cthread != cthread_self())
return FALSE;
else
#endif /* CONFIG_OSFMACH3_DEBUG */
return TRUE;
}