/* * @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; }