Jump to content
  • entries
    2
  • comments
    5
  • views
    1,014

Fair spinlock in papyrus


irquih

650 views

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

2 Comments


Recommended Comments

Don't think in C/C++ style when it comes to Papyrus. Your methods are creating unnecessary stress on the VM. Read this on how to create singletons/mutex for Papyrus.

Link to comment

I already read that, to write this code. :)  I actually assume anyone would, if they were going into locks for papyrus. This is more of an additional method.

 

As the title suggests, this is a fair spinlock. If you don't need fairness, you're probably better off with a simple bool. But if you need to guarantee your thread has access to a resource within a reasonable amount of time and you're having trouble making it work with a bool-only spinlock, this may be just what you need.

Link to comment
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more information, see our Privacy Policy & Terms of Use