VM_LOCK
is a GBVM instruction used to temporarily disable the switching of VM threads (contexts). When VM_LOCK
is active, the currently executing thread will run uninterrupted until VM_UNLOCK
is called or the thread yields control in a way that respects the lock.
Purpose:
In a multi-threaded environment, multiple threads can run concurrently, and the GBVM scheduler decides when to switch between them. While this is generally beneficial for responsiveness, there are critical sections of code where you need to ensure that only one thread is executing at a time to prevent data corruption or inconsistent states. VM_LOCK
is crucial for:
Syntax:
VM_LOCK
VM_LOCK
takes no arguments. It simply sets a flag within the GBVM scheduler to prevent thread switching.
Usage Example: Protecting a Critical Data Update
Imagine you have a global variable VAR_GAME_STATE_FLAGS
that stores multiple boolean flags (e.g., IS_PAUSED
, IS_IN_BATTLE
, HAS_ITEM_A
). Multiple threads might try to update these flags. To ensure that a sequence of updates is not interrupted, you can use VM_LOCK
.
; In a script that updates game state flags:
; Assume VAR_GAME_STATE_FLAGS is a 16-bit integer where each bit represents a flag
VAR_GAME_STATE_FLAGS:
.R_INT16 0
; --- Routine to set game to battle mode ---
SET_BATTLE_MODE:
VM_LOCK ; Acquire the lock
; Read current flags
VM_GET_INT16 VAR_TEMP_FLAGS, VAR_GAME_STATE_FLAGS
; Set the IS_IN_BATTLE flag (e.g., bit 1)
VM_RPN
.R_REF_MEM .R_INT16, VAR_TEMP_FLAGS ; Get current flags
.R_INT16 2 ; Value for bit 1 (00000010b)
.R_OPERATOR | ; Bitwise OR
.R_REF_MEM_SET .R_INT16, VAR_TEMP_FLAGS ; Store back to temp
VM_STOP
; Write updated flags back to global variable
VM_SET_INT16 VAR_GAME_STATE_FLAGS, VAR_TEMP_FLAGS
VM_UNLOCK ; Release the lock
VM_RET
; --- Another routine that might update a different flag ---
SET_PAUSED_MODE:
VM_LOCK ; Acquire the lock
; ... similar logic to set IS_PAUSED flag ...
VM_UNLOCK ; Release the lock
VM_RET
In this example, VM_LOCK
ensures that the sequence of reading VAR_GAME_STATE_FLAGS
, modifying it, and writing it back is completed without interruption from another thread. If another thread tries to acquire the lock while it’s held, it will typically wait until the lock is released.
Important Note: Every VM_LOCK
must eventually be paired with a VM_UNLOCK
to prevent deadlocks, where threads indefinitely wait for a resource that will never be released.
Analogy to other programming languages:
This is analogous to using mutexes, semaphores, or critical sections in multi-threaded programming (e.g., pthread_mutex_lock()
/pthread_mutex_unlock()
in C, synchronized
blocks in Java, threading.Lock
in Python). It’s a mechanism for mutual exclusion, ensuring that only one thread can execute a particular piece of code at any given time, thereby protecting shared data from corruption.