revert between 56095 -> 55830 in arch
[AROS.git] / arch / all-pc / kernel / spintrylock.c
blobf99cfd3ad0775f433d217a8f265f814310fe5ba7
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>
12 #define __KERNEL_NO_SPINLOCK_PROTOS__
13 #define __KERNEL_NOLIBBASE__
14 #include <proto/kernel.h>
15 #include <exec_platform.h>
17 #include <kernel_base.h>
18 #include <kernel_debug.h>
20 #define D(x)
22 int Kernel_13_KrnIsSuper();
24 AROS_LH2(spinlock_t *, KrnSpinTryLock,
25 AROS_LHA(spinlock_t *, lock, A0),
26 AROS_LHA(ULONG, mode, D0),
27 struct KernelBase *, KernelBase, 51, Kernel)
29 AROS_LIBFUNC_INIT
31 D(bug("[Kernel] %s(0x%p, %08x)\n", __func__, lock, mode));
33 if (mode == SPINLOCK_MODE_WRITE)
36 Check if lock->lock equals to SPINLOCK_UNLOCKED. If yes, it will be atomicaly replaced by SPINLOCKF_WRITE and function
37 returns 1. Otherwise it copies value of lock->lock into tmp and returns 0.
39 if (!compare_and_exchange_long((ULONG*)&lock->lock, SPINLOCK_UNLOCKED, SPINLOCKF_WRITE, NULL))
41 D(bug("[Kernel] %s: lock is held (value %08x). Failing to obtain it in WRITE mode...\n", __func__, lock->lock));
42 return NULL;
44 if (Kernel_13_KrnIsSuper())
46 lock->s_Owner = NULL;
48 else
50 lock->s_Owner = GET_THIS_TASK;
53 else
55 UBYTE tmp;
57 Check if upper 8 bits of lock->lock are all 0, which means spinlock is not in UPDATING state and it is not
58 in the WRITE state. If we manage to obtain it, we set the UPDATING flag. Until we release UPDATING state
59 we are free to do whatever we want with the spinlock
61 while (!compare_and_exchange_byte((UBYTE*)&lock->block[3], 0, SPINLOCKF_UPDATING >> 24, &tmp))
64 Obtaining lock in UPDATING mode failed. This can have two reasons - either the lock is in WRITE mode, in
65 which case we fail and return NULL. Eventually the lock can be in UPDATING mode already, in this case we
66 spin for a while...
68 if (tmp & (SPINLOCKF_WRITE >> 24))
70 D(bug("[Kernel] %s: lock is held in WRITE mode (value %08x). Failing to obtain it in READ mode...\n", __func__, lock->lock));
71 return NULL;
73 else
75 // Tell CPU we are spinning, it shouldn't take long - someone is just updating the lock in READ mode
76 asm volatile("pause");
78 D(bug("[Kernel] %s: spinning on updating lock ...\n", __func__));
82 At this point we have the spinlock in UPDATING state. So, update readcount field (no worry with atomic add,
83 spinlock is for our exclusive use here), and then release it just by setting updating flag to 0
85 WARNING: What to do if the 24-bit counter wraps?!
87 lock->slock.readcount++;
88 #if defined(AROS_NO_ATOMIC_OPERATIONS)
89 lock->slock.updating = 0;
90 #else
91 __AROS_ATOMIC_AND_L(lock->lock, ~SPINLOCKF_UPDATING);
92 #endif
95 D(bug("[Kernel] %s: lock = %08x\n", __func__, lock->lock));
97 return lock;
99 AROS_LIBFUNC_EXIT