Skip to content

Instantly share code, notes, and snippets.

@michaeljclark
Last active June 2, 2021 23:40
Show Gist options
  • Save michaeljclark/483df86b8ad1c5453098cdce8801c8b0 to your computer and use it in GitHub Desktop.
Save michaeljclark/483df86b8ad1c5453098cdce8801c8b0 to your computer and use it in GitHub Desktop.
Queued ticket lock description in English and some RISC-V assembly for a possible implementation
#pragma once
# Ticket Lock
#
# Ticket locks are fair spinlocks that order acccess on a first-in,
# first-out basis. The lock is composed of a head counter and a tail
# counter. The head counter indicates the ticket number of the current
# lock owner. The tail counter indicates the last issued ticket number.
# To acquire the lock, the acquiring thread atomically increments the
# tail counter to assign itself a ticket number. It then waits until
# its assigned ticket number is seen in the head counter. If the lock
# is not contended, then head will equal the ticket number just assigned.
# To release the lock, the lock owner atomically increments head counter
# thereby allowing access to the thread holding the next ticket number.
#
# Initializtion - the lock is initialized unlocked, so that the
# next tail increment returns a ticket that will acquires the lock.
#
# tail | head
# -------|-------
# 0x0000 | 0x0001
#
# Lock - the tail is incremented, and the thread waits unti the tail
# is equal to the head before returning control, which is the typical
# case if the lock is uncontended.
#
# tail | head
# -------|-------
# 0x0001 | 0x0001
#
# Unlock - the head is incremented, so that it will now equal the value
# of the ticket of the next waiter, if any.
#
# tail | head
# -------|-------
# 0x0001 | 0x0002
#
# Waiters - the number of waiters can be calculated by subtracting
# head (current ticket) from the tail plus one (next ticket)
#
# num_waiters = tail + 1 - head
#
spin_lock:
lui a2,0x10
amoadd.w a5,a5,(a0)
srliw a4,a5,0x10
2: slliw a5,a5,0x10
srliw a5,a5,0x10
bne a5,a4,3f
ret
3: lw a5,0(a0)
fence r,rw
j 2b
spin_trylock:
lui a5,0x10
lr.w.aq a4,(a0)
addw a5,a5,a4
slliw a3,a5,0x10
srliw a3,a3,0x10
srliw a4,a5,0x10
beq a3,a4,2f
1: li a0,0
ret
2: sc.w.rl a4,a5,(a0)
bnez a4,1b
fence r,rw
li a0,1
ret
spin_unlock:
fence rw,w
1: lr.w.aq a4,(a0)
srliw a5,a4,0x10
addiw a4,a4,1
slliw a4,a4,0x10
srliw a4,a4,0x10
slliw a5,a5,0x10
or a5,a5,a4
sc.w.rl a4,a5,(a0)
bnez a5,1b
ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment