This is a little snippet of code, that I've written in C and C++ before. This time it's for papyrus.
It's a ticket-based spinlock. For those with a comp-sci background, known as a ticket lock (Communicating Sequential Processes - C.A.R.Hoare, Chapter 6.6 Scheduling).
So what does it offer:
- it's a spinlock (i.e. a form of mutex)
- it's fair (the thread that waits the longest for the lock is the one that will acquire it next).
It provides 3 functions:
Function lock()
locks the resource (blocking)
Function unlock()
unlocks the resource (non-blocking)
bool Function trylock()
If the lock is available, will acquire the lock and return true; otherwise, it will fail and return false.
I.e. returns true if the lock attempt succeeds, false otherwise.
Feel free to include it in your mod.
;/Copyright (c) 2014, irquihAll rights reserved.Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE./;;;;;; Ticket spinlock;; NOTE: due to how papyrus works, these functions may only call methods in our script; NOTE: due to the script being locked (as long as no external functions are called); these functions can be treated as if they were atomics.; DO NOT REFACTOR TO EXTERNAL FUNCTIONS!int property spl_wrap_around_ = 0x7fffffff autoreadonlyint spl_ticket_ = 0int spl_cur_ = 0float property spl_wait_seconds_ = 0.05 autoreadonlyint spl_n_waiting = 0Function lock() debug.trace("DDRestrainedConfigQuest: Acquiring lock...") ; Acquire ticket int ticket = spl_ticket_ ; Update ticket if ticket == spl_wrap_around_ spl_ticket_ = 0 else spl_ticket_ += 1 endif ; Wait until spl_cur_ reaches our ticket spl_n_waiting += 1 int spl_spincount = 0 while spl_cur_ != ticket if spl_spincount == 100 || (spl_spincount != 0 && spl_spincount % 1000 == 0) debug.TraceStack("spl_spincount = " + spl_spincount + ", maybe deadlock? Currently " + spl_n_waiting + " blocked threads.", 1) ; Warn about slow lock access endif spl_spincount += 1 utility.WaitMenuMode(spl_wait_seconds_) endwhile debug.trace("DDRestrainedConfigQuest: Lock acquired after " + spl_spincount + " spins.") spl_n_waiting -= 1EndFunctionFunction unlock() if spl_cur_ == spl_wrap_around_ spl_cur_ = 0 else spl_cur_ += 1 endif debug.trace("DDRestrainedConfigQuest: Releasing lock...")EndFunctionbool Function trylock() if spl_cur_ != spl_ticket_ debug.trace("DDRestrainedConfigQuest: Trylock failed to acquire lock...") return false endif if spl_ticket_ == spl_wrap_around_ spl_ticket_ = 0 else spl_ticket_ += 1 endif debug.trace("DDRestrainedConfigQuest: Trylock successfully acquired lock...") return trueEndFunction
0
2 Comments
Recommended Comments