struct syscall's flags is now an atomic_t (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 14 Apr 2011 23:17:24 +0000 (16:17 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:01 +0000 (17:36 -0700)
Sparc needed this, since their atomic or works weirdly.  Also, it's a
bit safer in general.  Note, you shouldn't try to 'or' in flags in the
third byte, since sparc's atomics will break.

Rebuild your cross compiler.

kern/arch/i686/atomic.h
kern/arch/sparc/atomic.h
kern/include/ros/syscall.h
kern/src/syscall.c
tests/syscall.c
user/parlib/asynccall.c
user/parlib/uthread.c

index fd80173..1bbdc30 100644 (file)
@@ -25,12 +25,12 @@ static inline void atomic_dec(atomic_t *number);
 static inline long atomic_fetch_and_add(atomic_t *number, long val);
 static inline bool atomic_add_not_zero(atomic_t *number, long val);
 static inline bool atomic_sub_and_test(atomic_t *number, long val);
+static inline void atomic_or(atomic_t *number, int mask);
 static inline uint32_t atomic_swap(uint32_t *addr, uint32_t val);
 static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
                                     uint32_t new_val);
 static inline void atomic_andb(volatile uint8_t RACY* number, uint8_t mask);
 static inline void atomic_orb(volatile uint8_t RACY* number, uint8_t mask);
-static inline void atomic_or_int(volatile int *number, int mask);
 static inline uint32_t spin_locked(spinlock_t *SAFE lock);
 static inline void __spin_lock(volatile uint32_t SRACY*CT(1) rlock);
 static inline void spin_lock(spinlock_t *lock);
@@ -107,6 +107,11 @@ static inline bool atomic_sub_and_test(atomic_t *number, long val)
        return b;
 }
 
+static inline void atomic_or(atomic_t *number, int mask)
+{
+       asm volatile("lock orl %1,%0" : "=m"(*number) : "q"(mask) : "cc");
+}
+
 static inline uint32_t atomic_swap(uint32_t *addr, uint32_t val)
 {
        // this would work, but its code is bigger, and it's not like the others
@@ -140,11 +145,6 @@ static inline void atomic_orb(volatile uint8_t RACY*number, uint8_t mask)
        asm volatile("lock orb %1,%0" : "=m"(*number) : "q"(mask) : "cc");
 }
 
-static inline void atomic_or_int(volatile int *number, int mask)
-{
-       asm volatile("lock orl %1,%0" : "=m"(*number) : "q"(mask) : "cc");
-}
-
 static inline uint32_t spin_locked(spinlock_t *SAFE lock)
 {
        // the lock status is the lowest byte of the lock
index db283cc..ea5f8b1 100644 (file)
@@ -31,10 +31,10 @@ static inline void atomic_dec(atomic_t* number);
 static inline long atomic_fetch_and_add(atomic_t *number, long val);
 static inline bool atomic_add_not_zero(atomic_t *number, long val);
 static inline bool atomic_sub_and_test(atomic_t *number, long val);
+static inline void atomic_or(atomic_t *number, int mask);
 static inline uint32_t atomic_swap(uint32_t* addr, uint32_t val);
 static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
                                     uint32_t new_val);
-static inline void atomic_or_int(volatile int *number, int mask);
 static inline uint32_t spin_trylock(spinlock_t*SAFE lock);
 static inline uint32_t spin_locked(spinlock_t*SAFE lock);
 static inline void spin_lock(spinlock_t*SAFE lock);
@@ -127,6 +127,19 @@ static inline bool atomic_sub_and_test(atomic_t *number, long val)
        return retval;
 }
 
+static inline void atomic_or(atomic_t *number, int mask)
+{
+       int val;
+       /* this is pretty clever.  the lower 8 bits (i.e byte 3)
+        * of the atomic_t serve as a spinlock.  let's acquire it. */
+       spin_lock((spinlock_t*)number);
+       val = atomic_read(number);
+       /* compute new counter value. */
+       val |= mask;
+       /* set the new counter value.  the lock is cleared (for free) */
+       atomic_init(number, val);
+}
+
 static inline uint32_t atomic_swap(uint32_t* addr, uint32_t val)
 {
        __asm__ __volatile__ ("swap [%2],%0" : "=r"(val) : "0"(val),"r"(addr) : "memory");
@@ -152,19 +165,6 @@ static inline bool atomic_comp_swap(uint32_t *addr, uint32_t exp_val,
        return retval;
 }
 
-static inline void atomic_or_int(volatile int *number, int mask)
-{
-       int val;
-       /* this is pretty clever.  the lower 8 bits (i.e byte 3)
-        * of the atomic_t serve as a spinlock.  let's acquire it. */
-       spin_lock((spinlock_t*)number);
-       val = atomic_read((atomic_t*)number);
-       /* compute new counter value. */
-       val |= mask;
-       /* set the new counter value.  the lock is cleared (for free) */
-       atomic_init((atomic_t*)number, val);
-}
-
 static inline uint32_t spin_trylock(spinlock_t*SAFE lock)
 {
        uint32_t reg;
index 70a0304..28f6ff0 100644 (file)
@@ -5,8 +5,10 @@
 #include <ros/bits/syscall.h>
 #include <ros/arch/syscall.h>
 #include <ros/event.h>
+#include <arch/atomic.h>
 
-/* Flags for an individual syscall */
+/* Flags for an individual syscall.
+ * Careful, sparc can't handle flags in byte 3. */
 #define SC_DONE                                        0x0001          /* SC is done */
 #define SC_PROGRESS                            0x0002          /* SC made progress */
 #define SC_UEVENT                              0x0004          /* user has an ev_q */
@@ -15,7 +17,7 @@ struct syscall {
        unsigned int                            num;
        long                                            retval;
        int                                                     err;                    /* errno */
-       int                                                     flags;
+       atomic_t                                        flags;
        struct event_queue                      *ev_q;
        void                                            *u_data;
        long                                            arg0;
@@ -36,7 +38,7 @@ void ros_syscall_blockon(struct syscall *sysc);
  * spin, but in the future we could block the whole process. */
 static inline void __ros_syscall_blockon(struct syscall *sysc)
 {
-       while (!(sysc->flags & (SC_DONE | SC_PROGRESS)))
+       while (!(atomic_read(&sysc->flags) & (SC_DONE | SC_PROGRESS)))
                cpu_relax();
 }
 weak_alias(__ros_syscall_blockon, ros_syscall_blockon);
@@ -60,7 +62,7 @@ static inline long __ros_syscall(unsigned int _num, long _a0, long _a1, long _a2
        sysc.arg5 = _a5;
        num_started = __ros_arch_syscall(&sysc, 1);
        /* Don't proceed til we are done */
-       while (!(sysc.flags & SC_DONE))
+       while (!(atomic_read(&sysc.flags) & SC_DONE))
                ros_syscall_blockon(&sysc);
        if (errno_loc)
                *errno_loc = sysc.err;
index 5b8ec51..d565453 100644 (file)
@@ -75,7 +75,7 @@ static void signal_current_sc(int retval)
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
        assert(pcpui->cur_sysc);
        pcpui->cur_sysc->retval = retval;
-       pcpui->cur_sysc->flags |= SC_DONE;
+       atomic_or(&pcpui->cur_sysc->flags, SC_DONE); 
 }
 
 /* Callable by any function while executing a syscall (or otherwise, actually).
@@ -1438,7 +1438,7 @@ void run_local_syscall(struct syscall *sysc)
                               sysc->arg2, sysc->arg3, sysc->arg4, sysc->arg5);
        /* Atomically turn on the SC_DONE flag.  Need the atomics since we're racing
         * with userspace for the event_queue registration. */
-       atomic_or_int(&sysc->flags, SC_DONE); 
+       atomic_or(&sysc->flags, SC_DONE); 
        signal_syscall(sysc, pcpui->cur_proc);
        /* Can unpin (UMEM) at this point */
        pcpui->cur_sysc = 0;    /* no longer working on sysc */
@@ -1469,7 +1469,7 @@ void signal_syscall(struct syscall *sysc, struct proc *p)
        struct event_queue *ev_q;
        struct event_msg local_msg;
        /* User sets the ev_q then atomically sets the flag (races with SC_DONE) */
-       if (sysc->flags & SC_UEVENT) {
+       if (atomic_read(&sysc->flags) & SC_UEVENT) {
                rmb();
                ev_q = sysc->ev_q;
                if (ev_q) {
index 7e89c19..92922cc 100644 (file)
@@ -41,7 +41,7 @@ int main(int argc, char** argv)
        sysc.ev_q = ev_q;
        /* Trap */
        num_started = __ros_arch_syscall((long)&sysc, 1);
-       if (!(sysc.flags & SC_DONE))
+       if (!(atomic_read(&sysc.flags) & SC_DONE))
                printf("Not done, looping!\n");
        #if 0
        /* You could poll on this */
@@ -83,11 +83,11 @@ int main(int argc, char** argv)
        sysc.ev_q = ev_q;
        num_started = __ros_arch_syscall((long)&sysc, 1);
        /* have this thread "wait" */
-       if (!(sysc.flags & SC_DONE))
+       if (!(atomic_read(&sysc.flags) & SC_DONE))
                printf("Not done, looping on a local variable!\n");
        while (sysc.u_data)
                cpu_relax();
-       assert((sysc.flags & SC_DONE));
+       assert(atomic_read(&sysc.flags) & SC_DONE);
        printf("Syscall unblocked, IPI broke me out of the loop.\n");
 
        /* done */
@@ -106,7 +106,7 @@ static void handle_syscall(struct event_msg *ev_msg, unsigned int ev_type,
        printf("Handling syscall event for sysc %08p (%08p)\n",
               my_sysc, &sysc);
        /* our syscall should be done (we ought to check the msg pointer) */
-       if (sysc.flags & SC_DONE) 
+       if (atomic_read(&sysc.flags) & SC_DONE) 
                printf("Syscall is done, retval: %d\n", sysc.retval);
        else
                printf("BUG! Syscall wasn't done!\n");
index fb0e186..ab525fb 100644 (file)
@@ -201,7 +201,7 @@ int waiton_syscall(syscall_desc_t* desc)
        syscall_rsp_t* rsp = RING_GET_RESPONSE(fr, desc->idx);
 
        // ignoring the ring push response from the kernel side now
-       while (rsp->sc->flags != SC_DONE)
+       while (atomic_read(&rsp->sc->flags) != SC_DONE)
                cpu_relax();
        // memcpy(rsp, rsp_inring, sizeof(*rsp));
        
index d9a5b5c..d09c068 100644 (file)
@@ -251,7 +251,7 @@ void ros_syscall_blockon(struct syscall *sysc)
                return;
        }
        /* double check before doing all this crap */
-       if (sysc->flags & (SC_DONE | SC_PROGRESS))
+       if (atomic_read(&sysc->flags) & (SC_DONE | SC_PROGRESS))
                return;
        /* So yield knows we are blocking on something */
        assert(current_uthread);