revert between 56095 -> 55830 in arch
[AROS.git] / arch / all-pc / kernel / spinlock.c
blob8325ef11ec1738eb4461310f390575266166e5b4
1 /*
2 Copyright © 2017, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <asm/cpu.h>
7 #include <aros/atomic.h>
8 #include <aros/types/spinlock_s.h>
9 #include <aros/kernel.h>
10 #include <aros/libcall.h>
11 #include <utility/hooks.h>
13 #include <exec/tasks.h>
15 #define __KERNEL_NO_SPINLOCK_PROTOS__
16 #define __KERNEL_NOLIBBASE__
17 #include <proto/kernel.h>
18 #include <exec_platform.h>
20 #include <kernel_base.h>
21 #include <kernel_debug.h>
23 #define D(x)
25 int Kernel_13_KrnIsSuper();
27 AROS_LH3(spinlock_t *, KrnSpinLock,
28 AROS_LHA(spinlock_t *, lock, A1),
29 AROS_LHA(struct Hook *, failhook, A0),
30 AROS_LHA(ULONG, mode, D0),
31 struct KernelBase *, KernelBase, 52, Kernel)
33 AROS_LIBFUNC_INIT
35 D(bug("[Kernel] %s(0x%p, 0x%p, %08x)\n", __func__, lock, failhook, mode));
37 if (mode == SPINLOCK_MODE_WRITE)
39 ULONG tmp;
40 struct Task *me = NULL;
41 BYTE old_pri = 0;
42 UBYTE priority_changed = 0;
43 if (!Kernel_13_KrnIsSuper())
44 me = GET_THIS_TASK;
46 Check if lock->lock equals to SPINLOCK_UNLOCKED. If yes, it will be atomicaly replaced by SPINLOCKF_WRITE and function
47 returns 1. Otherwise it copies value of lock->lock into tmp and returns 0.
49 while (!compare_and_exchange_long((ULONG*)&lock->lock, SPINLOCK_UNLOCKED, SPINLOCKF_WRITE, &tmp))
51 struct Task *t = lock->s_Owner;
52 // Tell CPU we are spinning
53 asm volatile("pause");
55 // Call failhook if there is any
56 if (failhook)
58 D(bug("[Kernel] %s: lock-held ... calling fail hook @ 0x%p ...\n", __func__, failhook);)
59 CALLHOOKPKT(failhook, (APTR)lock, 0);
61 D(bug("[Kernel] %s: my name is %s\n", __func__, Kernel_13_KrnIsSuper() ? "--supervisor code--" : me->tc_Node.ln_Name));
62 D(bug("[Kernel] %s: spinning on held lock (val=%08x, s_Owner=%p)...\n", __func__, tmp, t));
63 if (me && t && (me->tc_Node.ln_Pri > t->tc_Node.ln_Pri))
65 D(bug("[Kernel] %s: spinlock owner (%s) has pri %d, lowering ours...\n", __func__, t ? (t->tc_Node.ln_Name) : "--supervisor--", t ? t->tc_Node.ln_Pri : 999));
66 // If lock is spinning and the owner of lock has lower priority than ours, we need to reduce
67 // tasks priority too, otherwise it might happen that waiting task spins forever
68 priority_changed = 1;
69 old_pri = SetTaskPri(me, t->tc_Node.ln_Pri);
72 if (Kernel_13_KrnIsSuper())
74 lock->s_Owner = NULL;
76 else
78 lock->s_Owner = me;
79 if (priority_changed)
80 SetTaskPri(me, old_pri);
83 else
86 Check if upper 8 bits of lock->lock are all 0, which means spinlock is not in UPDATING state and it is not
87 in the WRITE state. If we manage to obtain it, we set the UPDATING flag. Until we release UPDATING state
88 we are free to do whatever we want with the spinlock
90 while (!compare_and_exchange_byte((UBYTE*)&lock->block[3], 0, SPINLOCKF_UPDATING >> 24, NULL))
92 // Tell CPU we are spinning
93 asm volatile("pause");
95 // Call fail hook if available
96 if (failhook)
98 D(bug("[Kernel] %s: write-locked .. calling fail hook @ 0x%p ...\n", __func__, failhook);)
99 CALLHOOKPKT(failhook, (APTR)lock, 0);
101 D(bug("[Kernel] %s: spinning on write lock ...\n", __func__);)
105 At this point we have the spinlock in UPDATING state. So, update readcount field (no worry with atomic add,
106 spinlock is for our exclusive use here), and then release it just by setting updating flag to 0
108 lock->slock.readcount++;
109 #if defined(AROS_NO_ATOMIC_OPERATIONS)
110 lock->slock.updating = 0;
111 #else
112 __AROS_ATOMIC_AND_L(lock->lock, ~SPINLOCKF_UPDATING);
113 #endif
116 D(bug("[Kernel] %s: lock = %08x\n", __func__, lock->lock));
118 return lock;
120 AROS_LIBFUNC_EXIT