os161-1.99
 All Data Structures
spl.c
00001 /*
00002  * Copyright (c) 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 /* Make sure to build out-of-line versions of spl inline functions */
00031 #define SPL_INLINE      /* empty */
00032 
00033 #include <types.h>
00034 #include <lib.h>
00035 #include <cpu.h>
00036 #include <spl.h>
00037 #include <thread.h>
00038 #include <current.h>
00039 
00040 /*
00041  * Machine-independent interrupt handling functions.
00042  *
00043  * Traditionally, all this code is machine-dependent.
00044  *
00045  * However.
00046  *
00047  * Since on OS/161 we don't support interrupt levels on any platform,
00048  * all we require under this logic is cpu_irqoff() and cpu_irqon()
00049  * that explicitly turn interrupts off and on.
00050  *
00051  * If we had multiple interrupt levels, the number of levels would in
00052  * general be different on different platforms (depending on hardware
00053  * requirements and hardware capabilities) so things would get more
00054  * complicated -- but nearly all of this code could remain MI.
00055  */
00056 
00057 
00058 /*
00059  * Raise and lower the interrupt priority level.
00060  *
00061  * Each spinlock acquisition can raise and lower the priority level
00062  * independently. The spl calls also raise and lower the priority
00063  * level independently of the spinlocks. This is necessary because in
00064  * general spinlock acquisitions and releases don't nest perfectly,
00065  * and don't necessarily nest with respect to spl calls either.
00066  *
00067  * For example:
00068  *
00069  *    struct spinlock red, blue;
00070  *    int s;
00071  *
00072  *    spinlock_acquire(&red);
00073  *    s = splhigh();
00074  *    spinlock_acquire(&blue);
00075  *    splx(s);
00076  *    spinlock_release(&red);
00077  *    spinlock_release(&blue);
00078  *
00079  * In order to make this work we need to count the number of times
00080  * IPL_HIGH (or, if we had multiple interrupt priority levels, each
00081  * level independently) has been raised. Interrupts go off on the
00082  * first raise, and go on again only on the last lower.
00083  *
00084  * curthread->t_iplhigh_count is used to track this.
00085  */
00086 void
00087 splraise(int oldspl, int newspl)
00088 {
00089         struct thread *cur = curthread;
00090 
00091         /* only one priority level, only one valid args configuration */
00092         KASSERT(oldspl == IPL_NONE);
00093         KASSERT(newspl == IPL_HIGH);
00094 
00095         if (!CURCPU_EXISTS()) {
00096                 /* before curcpu initialization; interrupts are off anyway */
00097                 return;
00098         }
00099 
00100         if (cur->t_iplhigh_count == 0) {
00101                 cpu_irqoff();
00102         }
00103         cur->t_iplhigh_count++;
00104 }
00105 
00106 void
00107 spllower(int oldspl, int newspl)
00108 {
00109         struct thread *cur = curthread;
00110 
00111         /* only one priority level, only one valid args configuration */
00112         KASSERT(oldspl == IPL_HIGH);
00113         KASSERT(newspl == IPL_NONE);
00114 
00115         if (!CURCPU_EXISTS()) {
00116                 /* before curcpu initialization; interrupts are off anyway */
00117                 return;
00118         }
00119 
00120         cur->t_iplhigh_count--;
00121         if (cur->t_iplhigh_count == 0) {
00122                 cpu_irqon();
00123         }
00124 }
00125 
00126 
00127 /*
00128  * Disable or enable interrupts and adjust curspl setting. Return old
00129  * spl level.
00130  */
00131 int
00132 splx(int spl)
00133 {
00134         struct thread *cur = curthread;
00135         int ret;
00136 
00137         if (cur->t_curspl < spl) {
00138                 /* turning interrupts off */
00139                 splraise(cur->t_curspl, spl);
00140                 ret = cur->t_curspl;
00141                 cur->t_curspl = spl;
00142         }
00143         else if (cur->t_curspl > spl) {
00144                 /* turning interrupts on */
00145                 ret = cur->t_curspl;
00146                 cur->t_curspl = spl;
00147                 spllower(ret, spl);
00148         }
00149         else {
00150                 /* do nothing */
00151                 ret = spl;
00152         }
00153 
00154         return ret;
00155 }
 All Data Structures