Skip to content

spinlock: improve performance and add CONFIG_SPINLOCK_INLINE control - #21342

Open
Fix-Point wants to merge 11 commits into
apache:masterfrom
Fix-Point:nuttx-seqlock-spinlock-sync2
Open

Fix-Point wants to merge 11 commits into
apache:masterfrom
Fix-Point:nuttx-seqlock-spinlock-sync2

Conversation

@Fix-Point

@Fix-Point Fix-Point commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Note: Please adhere to Contributing Guidelines.

Summary

This PR improves spinlock/rspinlock performance and adds inline control:

  1. ticked_spinlock: Improve the performance of ticket spinlock — optimize ticket spinlock performance.
  2. spinlock: Improve the performance of rspinlock — restructure rspinlock with val/local_val fields and RSPINLOCK_* macros.
  3. spinlock: Add compiler_assume for rspinlock — add compiler hint optimization.
  4. spinlock: Fix Coverity CONSTANT_EXPRESSION_RESULT in rspin_lock — Coverity fix.
  5. spinlock: add CONFIG_SPINLOCK_INLINE to control inlining — add CONFIG_SPINLOCK_INLINE option to control inline vs non-inline helpers.
  6. spinlock: fix uninitialized ret in rspin_trylock — fix uninitialized return value.
  7. spinlock: Add WFE/SEV optimization to prevent livelock — add UP_WFE()/UP_SEV() optimization to prevent livelock.

Impact

  • Build process: adds CONFIG_SPINLOCK_INLINE Kconfig option (default !DEFAULT_SMALL).
  • Hardware: uses UP_WFE()/UP_SEV() (ARM/RISC-V low-power wait/event instructions) to prevent livelock; removes redundant UP_DSB() calls.
  • Performance: rspinlock uses local_val (local copy) to avoid atomic read/write; ticket spinlock optimized.
  • Compatibility: irq_save()/irq_restore() wrapper replaces up_irq_save()/up_irq_restore() calls (behavior unchanged).
  • Security: no impact.

Testing

  • Host machine: Linux x86_64
  • Board: rv-virt (QEMU RISC-V 32-bit)
  • Config: rv-virt:smp
  • Toolchain: riscv64-unknown-elf-gcc (rv32 multilib)
  • Test: compile (make) + QEMU ostest passed
➜   qemu-system-riscv32 -semihosting -M virt,aclint=on -cpu rv32 -smp 8 -bios none -nographic -kernel nuttx -s
nsh> ostest
stdio_test: write fd=1
stdio_test: Standard I/O Check: printf
stdio_test: write fd=2
stdio_test: Standard I/O Check: fprintf to stderr
ostest_main: putenv(Variable1=BadValue3)
ostest_main: setenv(Variable1, GoodValue1, TRUE)
ostest_main: setenv(Variable2, BadValue1, FALSE)
ostest_main: setenv(Variable2, GoodValue2, TRUE)
ostest_main: setenv(Variable3, GoodValue3, FALSE)
ostest_main: setenv(Variable3, BadValue2, FALSE)
show_variable: Variable=Variable1 has value=GoodValue1
show_variable: Variable=Variable2 has value=GoodValue2
show_variable: Variable=Variable3 has value=GoodValue3
ostest_main: Started user_main at PID=12

user_main: vfork() test
vfork_test: Started
vfork_test: Child 13 ran and exited before the parent resumed

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         1        1
mxordblk  1fc6880  1fc6880
uordblks     4ffc     4ffc
fordblks  1fc6880  1fc6880

user_main: Begin argument test
user_main: Started with argc=5
user_main: argv[0]="ostest"
user_main: argv[1]="Arg1"
user_main: argv[2]="Arg2"
user_main: argv[3]="Arg3"
user_main: argv[4]="Arg4"

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         1        1
mxordblk  1fc6880  1fc6880
uordblks     4ffc     4ffc
fordblks  1fc6880  1fc6880

user_main: getopt() test
getopt():  Simple test
getopt():  Invalid argument
getopt():  Missing optional argument
getopt_long():  Simple test
getopt_long():  No short options
getopt_long():  Argument for --option=argument
getopt_long():  Invalid long option
getopt_long():  Mixed long and short options
getopt_long():  Invalid short option
getopt_long():  Missing optional arguments
getopt_long_only():  Mixed long and short options
getopt_long_only():  Single hyphen long options

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         1        1
mxordblk  1fc6880  1fc6880
uordblks     4ffc     4ffc
fordblks  1fc6880  1fc6880

user_main: libc tests

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         1        1
mxordblk  1fc6880  1fc6880
uordblks     4ffc     4ffc
fordblks  1fc6880  1fc6880
show_variable: Variable=Variable1 has value=GoodValue1
show_variable: Variable=Variable2 has value=GoodValue2
show_variable: Variable=Variable3 has value=GoodValue3
show_variable: Variable=Variable1 has no value
show_variable: Variable=Variable2 has value=GoodValue2
show_variable: Variable=Variable3 has value=GoodValue3

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         1        1
mxordblk  1fc6880  1fc6880
uordblks     4ffc     4ffc
fordblks  1fc6880  1fc6880
show_variable: Variable=Variable1 has no value
show_variable: Variable=Variable2 has no value
show_variable: Variable=Variable3 has no value

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         1        2
mxordblk  1fc6880  1fc6880
uordblks     4ffc     4fcc
fordblks  1fc6880  1fc68b0

user_main: setvbuf test
setvbuf_test: Test NO buffering
setvbuf_test: Using NO buffering
setvbuf_test: Test default FULL buffering
setvbuf_test: Using default FULL buffering
setvbuf_test: Test FULL buffering, buffer size 64
setvbuf_test: Using FULL buffering, buffer size 64
setvbuf_test: Test FULL buffering, pre-allocated buffer
setvbuf_test: Using FULL buffering, pre-allocated buffer
setvbuf_test: Test LINE buffering, buffer size 64
setvbuf_test: Using LINE buffering, buffer size 64
setvbuf_test: Test FULL buffering, pre-allocated buffer
setvbuf_test: Using FULL buffering, pre-allocated buffer

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         2        2
mxordblk  1fc6880  1fc6880
uordblks     4fcc     4fcc
fordblks  1fc68b0  1fc68b0

user_main: FPU test
Starting task FPU#1
fpu_test: Started task FPU#1 at PID=14
FPU#1: pass 1
Starting task FPU#2
fpu_test: Started task FPU#2 at PID=15
FPU#2: pass 1
FPU#1: pass 2
FPU#2: pass 2
FPU#1: pass 3
FPU#2: pass 3
FPU#1: pass 4
FPU#2: pass 4
FPU#1: pass 5
FPU#2: pass 5
FPU#1: pass 6
FPU#2: pass 6
FPU#1: pass 7
FPU#2: pass 7
FPU#1: pass 8
FPU#2: pass 8
FPU#1: pass 9
FPU#2: pass 9
FPU#1: pass 10
FPU#2: pass 10
FPU#1: pass 11
FPU#2: pass 11
FPU#1: pass 12
FPU#2: pass 12
FPU#1: pass 13
FPU#2: pass 13
FPU#1: pass 14
FPU#2: pass 14
FPU#1: pass 15
FPU#2: pass 15
FPU#1: pass 16
FPU#2: pass 16
FPU#1: Succeeded
FPU#2: Succeeded
fpu_test: Returning

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         2        2
mxordblk  1fc6880  1fc6880
uordblks     4fcc     4fcc
fordblks  1fc68b0  1fc68b0

user_main: task_restart test

Test task_restart()
restart_main: setenv(VarName, VarValue, TRUE)
restart_main: Started restart_main at PID=24
restart_main: Started with argc=4
restart_main: argv[0]="ostest"
restart_main: argv[1]="This is argument 1"
restart_main: argv[2]="Argument 2 here"
restart_main: argv[3]="Lastly, the 3rd argument"
restart_main: Variable=VarName has value=VarValue
restart_main: I am still here
restart_main: I am still here
restart_main: Started restart_main at PID=24
restart_main: Started with argc=4
restart_main: argv[0]="ostest"
restart_main: argv[1]="This is argument 1"
restart_main: argv[2]="Argument 2 here"
restart_main: argv[3]="Lastly, the 3rd argument"
restart_main: Variable=VarName has value=VarValue
restart_main: Started with argc=4
restart_main: argv[0]="ostest"
restart_main: argv[1]="This is argument 1"
restart_main: argv[2]="Argument 2 here"
restart_main: argv[3]="Lastly, the 3rd argument"
restart_main: Variable=VarName has value=VarValue
restart_main: Exiting

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         2        2
mxordblk  1fc6880  1fc6860
uordblks     4fcc     500c
fordblks  1fc68b0  1fc6870

user_main: waitpid test

Test waitpid()
waitpid_start_child: Started waitpid_main at PID=29
waitpid_start_child: Started waitpid_main at PID=30
waitpid_main: PID 29 Started
waitpid_main: PID 30 Started
waitpid_start_child: Started waitpid_main at PID=31
waitpid_main: PID 31 Started
waitpid_test: Waiting for PID=29 with waitpid()
waitpid_main: PID 29 exiting with result=14
waitpid_main: PID 30 exiting with result=14
waitpid_main: PID 31 exiting with result=14
waitpid_test: PID 29 waitpid succeeded with stat_loc=0e00
waitpid_last: Waiting for PID=31 with waitpid()
waitpid_last: PASS: PID 31 waitpid succeeded with stat_loc=0e00

Test waitid(P_PID)
waitpid_start_child: Started waitpid_main at PID=40
waitpid_main: PID 40 Started
waitpid_start_child: Started waitpid_main at PID=45
waitpid_main: PID 45 Started
waitpid_start_child: Started waitpid_main at PID=46
waitpid_main: PID 46 Started
waitpid_test: Waiting for PID=40 with waitid()
waitpid_main: PID 40 exiting with result=14
waitpid_main: PID 45 exiting with result=14
waitpid_test: waitid PID 40 succeeded with si_status=14
waitpid_main: PID 46 exiting with result=14
waitpid_last: Waiting for PID=46 with waitpid()
waitpid_last: PASS: PID 46 waitpid succeeded with stat_loc=0e00

Test waitid(P_ALL)
waitpid_start_child: Started waitpid_main at PID=47
waitpid_main: PID 47 Started
waitpid_start_child: Started waitpid_main at PID=56
waitpid_main: PID 56 Started
waitpid_start_child: Started waitpid_main at PID=61
waitpid_main: PID 61 Started
waitpid_test: Waiting for any child with waitid()
waitpid_test: PID 45 waitid succeeded with si_status=14
waitpid_last: Waiting for PID=61 with waitpid()
waitpid_main: PID 47 exiting with result=14
waitpid_main: PID 56 exiting with result=14
waitpid_main: PID 61 exiting with result=14
waitpid_last: PASS: PID 61 waitpid succeeded with stat_loc=0e00

Test wait()
waitpid_start_child: Started waitpid_main at PID=62
waitpid_start_child: Started waitpid_main at PID=63
waitpid_main: PID 62 Started
waitpid_main: PID 63 Started
waitpid_start_child: Started waitpid_main at PID=72
waitpid_main: PID 72 Started
waitpid_test: Waiting for any child with wait()
waitpid_test: PID 56 wait succeeded with stat_loc=0e00
waitpid_last: Waiting for PID=72 with waitpid()
waitpid_main: PID 62 exiting with result=14
waitpid_main: PID 63 exiting with result=14
waitpid_main: PID 72 exiting with result=14
waitpid_last: PASS: PID 72 waitpid succeeded with stat_loc=0e00

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         2        7
mxordblk  1fc6860  1fbbce0
uordblks     500c     d38c
fordblks  1fc6870  1fbe4f0

user_main: mutex test
Initializing mutex
Starting thread 1
Starting thread 2
		Thread1	Thread2
	Loops	32	32
	Errors	0	0

Testing moved mutex
Starting moved mutex thread 1
Starting moved mutex thread 2
		Thread1	Thread2
	Moved Loops	32	32
	Moved Errors	0	0

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         7        3
mxordblk  1fbbce0  1fc4840
uordblks     d38c     61dc
fordblks  1fbe4f0  1fc56a0

user_main: timed mutex test
mutex_test: Initializing mutex
mutex_test: Starting thread
pthread:  Started
pthread:  Waiting for lock or timeout
mutex_test: Unlocking
pthread:  Got the lock
pthread:  Waiting for lock or timeout
pthread:  Got the timeout.  Terminating
mutex_test: PASSED
timedmutex regression test: PASSED

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         3        4
mxordblk  1fc4840  1fc4038
uordblks     61dc     6ac4
fordblks  1fc56a0  1fc4db8

user_main: cancel test
cancel_test: Test 1a: Normal Cancellation
cancel_test: Starting thread
start_thread: Initializing mutex
start_thread: Initializing cond
start_thread: Starting thread
start_thread: Yielding
sem_waiter: Taking mutex
sem_waiter: Starting wait for condition
cancel_test: Canceling thread
cancel_test: Joining
cancel_test: waiter exited with result=0xffffffff
cancel_test: PASS thread terminated with PTHREAD_CANCELED
cancel_test: Test 2: Asynchronous Cancellation
... Skipped
cancel_test: Test 3: Cancellation of detached thread
cancel_test: Re-starting thread
restart_thread: Destroying cond
restart_thread: Destroying mutex
restart_thread: Re-starting thread
start_thread: Initializing mutex
start_thread: Initializing cond
start_thread: Starting thread
start_thread: Yielding
sem_waiter: Taking mutex
sem_waiter: Starting wait for condition
cancel_test: Canceling thread
cancel_test: Joining
cancel_test: PASS pthread_join failed with status=ESRCH
cancel_test: Test 5: Non-cancelable threads
cancel_test: Re-starting thread (non-cancelable)
restart_thread: Destroying cond
restart_thread: Destroying mutex
restart_thread: Re-starting thread
start_thread: Initializing mutex
start_thread: Initializing cond
start_thread: Starting thread
start_thread: Yielding
sem_waiter: Taking mutex
sem_waiter: Starting wait for condition
sem_waiter: Setting non-cancelable
cancel_test: Canceling thread
cancel_test: Joining
sem_waiter: Releasing mutex
sem_waiter: Setting cancelable
cancel_test: waiter exited with result=0xffffffff
cancel_test: PASS thread terminated with PTHREAD_CANCELED
cancel_test: Test 6: Cancel message queue wait
cancel_test: Starting thread (cancelable)
Skipped
cancel_test: Test 7: Cancel signal wait
cancel_test: Starting thread (cancelable)
Skipped

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         4        4
mxordblk  1fc4038  1fc4038
uordblks     6ac4     6ac4
fordblks  1fc4db8  1fc4db8

user_main: semaphore test
sem_test: Initializing semaphore to 0
sem_test: Starting waiter thread 1
sem_test: Set thread 1 priority to 191
sem_test: Starting waiter thread 2
waiter_func: Thread 1 Started
sem_test: Set thread 2 priority to 128
waiter_func: Thread 1 initial semaphore value = 0
waiter_func: Thread 1 waiting on semaphore
waiter_func: Thread 2 Started
waiter_func: Thread 2 initial semaphore value = -1
waiter_func: Thread 2 waiting on semaphore
sem_test: Starting poster thread 3
sem_test: Set thread 3 priority to 64
poster_func: Thread 3 started
poster_func: Thread 3 semaphore value = -2
poster_func: Thread 3 posting semaphore
poster_func: Thread 3 new semaphore value = -1
waiter_func: Thread 1 awakened
poster_func: Thread 3 semaphore value = -1
waiter_func: Thread 1 new semaphore value = -1
poster_func: Thread 3 posting semaphore
waiter_func: Thread 1 done
waiter_func: Thread 2 awakened
poster_func: Thread 3 new semaphore value = 0
waiter_func: Thread 2 new semaphore value = 0
poster_func: Thread 3 done
waiter_func: Thread 2 done

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         4        4
mxordblk  1fc4038  1fc4038
uordblks     6ac4     6ac4
fordblks  1fc4db8  1fc4db8

user_main: timed semaphore test
semtimed_test: Initializing semaphore to 0
semtimed_test: Waiting for two second timeout
semtimed_test: PASS: first test returned timeout
BEFORE: (1638316852 sec, 167195300 nsec)
AFTER:  (1638316854 sec, 167470400 nsec)
semtimed_test: Starting poster thread
semtimed_test: Set thread 1 priority to 191
semtimed_test: Starting poster thread 3
semtimed_test: Set thread 3 priority to 64
semtimed_test: Waiting for two second timeout
poster_func: Waiting for 1 second
poster_func: Posting
semtimed_test: PASS: sem_timedwait succeeded
BEFORE: (1638316854 sec, 168106700 nsec)
AFTER:  (1638316855 sec, 169582300 nsec)

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         4        4
mxordblk  1fc4038  1fc4840
uordblks     6ac4     6ac4
fordblks  1fc4db8  1fc4db8

user_main: condition variable test
cond_test: Initializing mutex
cond_test: Initializing cond
cond_test: Starting waiter
cond_test: Set thread 1 priority to 128
waiter_thread: Started
cond_test: Starting signaler
cond_test: Set thread 2 priority to 64
thread_signaler: Started
thread_signaler: Terminating
cond_test: signaler terminated, now cancel the waiter
cond_test: 	Waiter	Signaler
cond_test: Loops	32	32
cond_test: Errors	0	0
cond_test:
cond_test: 0 times, waiter did not have to wait for data
cond_test: 0 times, data was already available when the signaler run
cond_test: 0 times, the waiter was in an unexpected state when the signaler ran

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         4        4
mxordblk  1fc4840  1fc4840
uordblks     6ac4     6ac4
fordblks  1fc4db8  1fc4db8

user_main: pthread_exit() test
pthread_exit_test: Started pthread_exit_main at PID=142
pthread_exit_main 142: Starting pthread_exit_thread
pthread_exit_main 142: Sleeping for 5 seconds
pthread_exit_thread 143: Sleeping for 10 second
pthread_exit_main 142: Calling pthread_exit()
pthread_exit_thread 143: Still running...

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         4        5
mxordblk  1fc4840  1fc2030
uordblks     6ac4     73ac
fordblks  1fc4db8  1fc44d0

user_main: pthread_rwlock test
pthread_rwlock: Initializing rwlock
pthread_exit_thread 143: Exiting

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         5        2
mxordblk  1fc2030  1fc4840
uordblks     73ac     61ec
fordblks  1fc44d0  1fc5690

user_main: pthread_rwlock_cancel test
pthread_rwlock_cancel: Starting test

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         2        2
mxordblk  1fc4840  1fc4840
uordblks     61ec     61ec
fordblks  1fc5690  1fc5690

user_main: timed wait test
thread_waiter: Initializing mutex
timedwait_test: Initializing cond
timedwait_test: Starting waiter
timedwait_test: Set thread 2 priority to 177
timedwait_test: Joining
thread_waiter: Taking mutex
thread_waiter: Starting 5 second wait for condition
thread_waiter: pthread_cond_timedwait timed out
thread_waiter: Releasing mutex
thread_waiter: Exit with status 0x12345678
timedwait_test: waiter exited with result=0x12345678

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         2        2
mxordblk  1fc4840  1fc4840
uordblks     61ec     61ec
fordblks  1fc5690  1fc5690

user_main: timed message queue test
timedmqueue_test: Starting sender
timedmqueue_test: Waiting for sender to complete
sender_thread: Starting
sender_thread: mq_timedsend succeeded on msg 0
sender_thread: mq_timedsend succeeded on msg 1
sender_thread: mq_timedsend succeeded on msg 2
sender_thread: mq_timedsend succeeded on msg 3
sender_thread: mq_timedsend succeeded on msg 4
sender_thread: mq_timedsend succeeded on msg 5
sender_thread: mq_timedsend succeeded on msg 6
sender_thread: mq_timedsend succeeded on msg 7
sender_thread: mq_timedsend succeeded on msg 8
sender_thread: mq_timedsend 9 timed out as expected
sender_thread: returning nerrors=0
timedmqueue_test: Starting receiver
timedmqueue_test: Waiting for receiver to complete
receiver_thread: Starting
receiver_thread: mq_timedreceive succeed on msg 0
receiver_thread: mq_timedreceive succeed on msg 1
receiver_thread: mq_timedreceive succeed on msg 2
receiver_thread: mq_timedreceive succeed on msg 3
receiver_thread: mq_timedreceive succeed on msg 4
receiver_thread: mq_timedreceive succeed on msg 5
receiver_thread: mq_timedreceive succeed on msg 6
receiver_thread: mq_timedreceive succeed on msg 7
receiver_thread: mq_timedreceive succeed on msg 8
receiver_thread: Receive 9 timed out as expected
receiver_thread: returning nerrors=0
timedmqueue_test: Test complete

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         2        3
mxordblk  1fc4840  1fc4840
uordblks     61ec     6254
fordblks  1fc5690  1fc5628

user_main: sigprocmask test
sigprocmask_test: SUCCESS

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         3        3
mxordblk  1fc4840  1fc4840
uordblks     6254     6254
fordblks  1fc5628  1fc5628

user_main: message queue test
mqueue_test: Starting receiver
mqueue_test: Set receiver priority to 128
mqueue_test: Starting sender
receiver_thread: Starting
mqueue_test: Set sender thread priority to 64
mqueue_test: Waiting for sender to complete
sender_thread: Starting
sender_thread: mq_send succeeded on msg 0
sender_thread: mq_send succeeded on msg 1
receiver_thread: mq_receive succeeded on msg 0
sender_thread: mq_send succeeded on msg 2
receiver_thread: mq_receive succeeded on msg 1
sender_thread: mq_send succeeded on msg 3
receiver_thread: mq_receive succeeded on msg 2
sender_thread: mq_send succeeded on msg 4
receiver_thread: mq_receive succeeded on msg 3
sender_thread: mq_send succeeded on msg 5
receiver_thread: mq_receive succeeded on msg 4
sender_thread: mq_send succeeded on msg 6
receiver_thread: mq_receive succeeded on msg 5
sender_thread: mq_send succeeded on msg 7
receiver_thread: mq_receive succeeded on msg 6
sender_thread: mq_send succeeded on msg 8
receiver_thread: mq_receive succeeded on msg 7
sender_thread: mq_send succeeded on msg 9
receiver_thread: mq_receive succeeded on msg 8
sender_thread: returning nerrors=0
receiver_thread: mq_receive succeeded on msg 9
mqueue_test: Killing receiver
receiver_thread: mq_receive interrupted!
receiver_thread: returning nerrors=0
mqueue_test: Canceling receiver
mqueue_test: receiver has already terminated

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         3        3
mxordblk  1fc4840  1fc4840
uordblks     6254     6254
fordblks  1fc5628  1fc5628

user_main: spinlock test
spinlock_test: start......
Thread num: 1, Loop times: 1000000

Test type: spinlock
spinlock: Test Results:
spinlock: Final counter: 1000000
spinlock: Average throughput : 16243681 op/s
spinlock: Total execution time: 61792000 ns
 
Test type: rspinlock
rspinlock: Test Results:
rspinlock: Final counter: 1000000
rspinlock: Average throughput : 23691854 op/s
rspinlock: Total execution time: 42393400 ns
 
Test type: seqcount
seqcount: Test Results:
seqcount: Final counter: 1000000
seqcount: Average throughput : 18762148 op/s
seqcount: Total execution time: 53441300 ns
 
Thread num: 2, Loop times: 1000000

Test type: spinlock
spinlock: Test Results:
spinlock: Final counter: 2000000
spinlock: Average throughput : 7018536 op/s
spinlock: Total execution time: 142683300 ns
 
Test type: rspinlock
rspinlock: Test Results:
rspinlock: Final counter: 2000000
rspinlock: Average throughput : 3182490 op/s
rspinlock: Total execution time: 315057600 ns
 
Test type: seqcount
seqcount: Test Results:
seqcount: Final counter: 2000000
seqcount: Average throughput : 3492711 op/s
seqcount: Total execution time: 287520500 ns
 
Thread num: 3, Loop times: 1000000

Test type: spinlock
spinlock: Test Results:
spinlock: Final counter: 3000000
spinlock: Average throughput : 2165828 op/s
spinlock: Total execution time: 470229300 ns
 
Test type: rspinlock
rspinlock: Test Results:
rspinlock: Final counter: 3000000
rspinlock: Average throughput : 1726387 op/s
rspinlock: Total execution time: 587484700 ns
 
Test type: seqcount
seqcount: Test Results:
seqcount: Final counter: 3000000
seqcount: Average throughput : 1741857 op/s
seqcount: Total execution time: 583654500 ns
 
Thread num: 4, Loop times: 1000000

Test type: spinlock
spinlock: Test Results:
spinlock: Final counter: 4000000
spinlock: Average throughput : 1262215 op/s
spinlock: Total execution time: 794492900 ns
 
Test type: rspinlock
rspinlock: Test Results:
rspinlock: Final counter: 4000000
rspinlock: Average throughput : 1094024 op/s
rspinlock: Total execution time: 931201700 ns
 
Test type: seqcount
seqcount: Test Results:
seqcount: Final counter: 4000000
seqcount: Average throughput : 1128316 op/s
seqcount: Total execution time: 910869400 ns
 
Thread num: 5, Loop times: 1000000

Test type: spinlock
spinlock: Test Results:
spinlock: Final counter: 5000000
spinlock: Average throughput : 906827 op/s
spinlock: Total execution time: 1108253100 ns
 
Test type: rspinlock
rspinlock: Test Results:
rspinlock: Final counter: 5000000
rspinlock: Average throughput : 818328 op/s
rspinlock: Total execution time: 1258367000 ns
 
Test type: seqcount
seqcount: Test Results:
seqcount: Final counter: 5000000
seqcount: Average throughput : 842707 op/s
seqcount: Total execution time: 1251381200 ns
 
Thread num: 6, Loop times: 1000000

Test type: spinlock
spinlock: Test Results:
spinlock: Final counter: 6000000
spinlock: Average throughput : 433003 op/s
spinlock: Total execution time: 2341306300 ns
 
Test type: rspinlock
rspinlock: Test Results:
rspinlock: Final counter: 6000000
rspinlock: Average throughput : 598416 op/s
rspinlock: Total execution time: 1721477900 ns
 
Test type: seqcount
seqcount: Test Results:
seqcount: Final counter: 6000000
seqcount: Average throughput : 653046 op/s
seqcount: Total execution time: 1647012100 ns
 
Thread num: 7, Loop times: 1000000

Test type: spinlock
spinlock: Test Results:
spinlock: Final counter: 7000000
spinlock: Average throughput : 485457 op/s
spinlock: Total execution time: 2116638300 ns
 
Test type: rspinlock
rspinlock: Test Results:
rspinlock: Final counter: 7000000
rspinlock: Average throughput : 473032 op/s
rspinlock: Total execution time: 2165514500 ns
 
Test type: seqcount
seqcount: Test Results:
seqcount: Final counter: 7000000
seqcount: Average throughput : 469656 op/s
seqcount: Total execution time: 2242193700 ns
 
Thread num: 8, Loop times: 1000000

Test type: spinlock
spinlock: Test Results:
spinlock: Final counter: 8000000
spinlock: Average throughput : 358278 op/s
spinlock: Total execution time: 2903284000 ns
 
Test type: rspinlock
rspinlock: Test Results:
rspinlock: Final counter: 8000000
rspinlock: Average throughput : 381868 op/s
rspinlock: Total execution time: 2750571100 ns
 
Test type: seqcount
seqcount: Test Results:
seqcount: Final counter: 8000000
seqcount: Average throughput : 373495 op/s
seqcount: Total execution time: 2772067300 ns
 
spinlock_test: end......

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         3        7
mxordblk  1fc4840  1fb14e8
uordblks     6254    164dc
fordblks  1fc5628  1fb53a0

user_main: wdog test
wdog_test start...
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 0 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 1 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 10 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 100 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 1000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 10000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 100000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wdtest_once 1000000 ns
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wdtest_recursive 1000000ns
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wd_start with maximum delay, cancel OK, rest 2305843009213693948
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
wdtest_recursive 1000000ns
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
recursive wdog triggered 51 times, elapsed tick 102
wdtest_recursive 10000000ns
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
wdtest_recursive 10000000ns
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
recursive wdog triggered 51 times, elapsed tick 102
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
wdtest_recursive 10000000ns
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
recursive wdog triggered 9 times, elapsed tick 99
wdog_test end...

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         7        8
mxordblk  1fb14e8  1fa58d8
uordblks    164dc     9884
fordblks  1fb53a0  1fc1ff8

user_main: round-robin scheduler test
rr_test: Set thread priority to 1
rr_test: Set thread policy to SCHED_RR
rr_test: Starting first get_primes_thread
         First get_primes_thread: 487
rr_test: Starting second get_primes_thread
         Second get_primes_thread: 488
rr_test: Waiting for 10 time slices of each thread
         If RR scheduling is working, the threads run the same
         number of time slices
get_primes_thread id=1 started, looking for primes < 30000, running 10 time slice(s)
get_primes_thread id=2 started, looking for primes < 30000, running 10 time slice(s)
get_primes_thread id=2 finished, 10 time slice(s), found 161832 primes
get_primes_thread id=1 finished, 11 time slice(s), found 177014 primes
rr_test: thread 1 ran 11 time slices, thread 2 ran 10
rr_test: Done

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         8        8
mxordblk  1fa58d8  1fa58d8
uordblks     9884     9884
fordblks  1fc1ff8  1fc1ff8

user_main: barrier test
barrier_test: Initializing barrier
barrier_test: Thread 0 created
barrier_func: Thread 0 started
barrier_test: Thread 1 created
barrier_func: Thread 1 started
barrier_test: Thread 2 created
barrier_func: Thread 2 started
barrier_test: Thread 3 created
barrier_func: Thread 3 started
barrier_test: Thread 4 created
barrier_func: Thread 4 started
barrier_test: Thread 5 created
barrier_func: Thread 5 started
barrier_test: Thread 6 created
barrier_func: Thread 6 started
barrier_test: Thread 7 created
barrier_func: Thread 7 started
barrier_func: Thread 0 calling pthread_barrier_wait()
barrier_func: Thread 1 calling pthread_barrier_wait()
barrier_func: Thread 2 calling pthread_barrier_wait()
barrier_func: Thread 3 calling pthread_barrier_wait()
barrier_func: Thread 4 calling pthread_barrier_wait()
barrier_func: Thread 5 calling pthread_barrier_wait()
barrier_func: Thread 6 calling pthread_barrier_wait()
barrier_func: Thread 7 calling pthread_barrier_wait()
barrier_func: Thread 7, back with status=PTHREAD_BARRIER_SERIAL_THREAD (I AM SPECIAL)
barrier_func: Thread 0, back with status=0 (I am not special)
barrier_func: Thread 2, back with status=0 (I am not special)
barrier_func: Thread 3, back with status=0 (I am not special)
barrier_func: Thread 4, back with status=0 (I am not special)
barrier_func: Thread 1, back with status=0 (I am not special)
barrier_func: Thread 5, back with status=0 (I am not special)
barrier_func: Thread 6, back with status=0 (I am not special)
barrier_func: Thread 7 done
barrier_func: Thread 0 done
barrier_func: Thread 2 done
barrier_func: Thread 3 done
barrier_func: Thread 4 done
barrier_func: Thread 1 done
barrier_func: Thread 5 done
barrier_test: Thread 0 completed with result=0
barrier_test: Thread 1 completed with result=0
barrier_test: Thread 2 completed with result=0
barrier_test: Thread 3 completed with result=0
barrier_func: Thread 6 done
barrier_test: Thread 4 completed with result=0
barrier_test: Thread 5 completed with result=0
barrier_test: Thread 6 completed with result=0
barrier_test: Thread 7 completed with result=0

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         8        9
mxordblk  1fa58d8  1fa9730
uordblks     9884     9884
fordblks  1fc1ff8  1fc1ff8

user_main: scheduler lock test
sched_lock: Starting lowpri_thread at 97
sched_lock: Set lowpri_thread priority to 97
sched_lock: Starting highpri_thread at 98
sched_lock: Set highpri_thread priority to 98
sched_lock: Waiting...
sched_lock: PASSED No pre-emption occurred while scheduler was locked.
sched_lock: Starting lowpri_thread at 97
sched_lock: Set lowpri_thread priority to 97
sched_lock: Starting highpri_thread at 98
sched_lock: Set highpri_thread priority to 98
sched_lock: Waiting...
sched_lock: PASSED No pre-emption occurred while scheduler was locked.
sched_lock: Finished

End of test memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         9        9
mxordblk  1fa9730  1fa9730
uordblks     9884     9884
fordblks  1fc1ff8  1fc1ff8

user_main: smp call test
smp_call_test: Test start
smp_call_test: Call cpu 0, nowait
smp_call_test: Call cpu 0, wait
smp_call_test: Call cpu 1, nowait
smp_call_test: Call cpu 1, wait
smp_call_test: Call cpu 2, nowait
smp_call_test: Call cpu 2, wait
smp_call_test: Call cpu 3, nowait
smp_call_test: Call cpu 3, wait
smp_call_test: Call cpu 4, nowait
smp_call_test: Call cpu 4, wait
smp_call_test: Call cpu 5, nowait
smp_call_test: Call cpu 5, wait
smp_call_test: Call cpu 6, nowait
smp_call_test: Call cpu 6, wait
smp_call_test: Call cpu 7, nowait
smp_call_test: Call cpu 7, wait
smp_call_test: Call multi cpu, nowait
smp_call_test: Call in interrupt, wait
smp_call_test: Call multi cpu, wait
smp_call_test: Test success

Final memory usage:
VARIABLE  BEFORE   AFTER
======== ======== ========
arena     1fcb87c  1fcb87c
ordblks         1        9
mxordblk  1fc6880  1fa9730
uordblks     4ffc     9884
fordblks  1fc6880  1fc1ff8
user_main: Exiting
ostest_main: Exiting with status 0
nsh> 

simple spinlock time: 21 ns
ticked spinlock time: 35 ns
ticked spinlock time(opt): 29 ns

Assisted-By: mimo-v2.6-pro
Signed-off-by: hujun5 <hujun5@xiaomi.com>
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

MemBrowse Memory Report · Explore what changed →

arduino-mega2560

  • flash: .text -84 B (-0.1%, 66,225 B / 262,144 B, total: 25% used)

esp32-devkitc

  • ROM: .flash.text -32 B (-0.0%, 129,084 B / 4,194,272 B, total: 3% used)
  • irom0_0_seg: .flash.text -32 B (-0.0%, 94,932 B / 3,342,304 B, total: 3% used)

mirtoo

  • kseg0_progmem: .text -28 B (-0.0%, 68,380 B / 131,072 B, total: 52% used)

qemu-armv8a

  • Code: .text.clock_notifier_call_chain -12 B, .text.group_allocate -52 B, .text.load_module +60 B, .text.nsh_command -16 B, .text.nx_start -12 B, .text.panic_notifier_call_chain -12 B, .text.panic_notifier_chain_register -8 B, .text.reboot_notifier_call_chain -12 B, .text.register_reboot_notifier -8 B, .text.rspinlock_t_test_thread +4 B, .text.syslog_write +4 B, .text.tmpfs_open -4 B, .text.tmpfs_rmdir +8 B (-0.0%, 360,192 B)

rx65n-rsk2mb

  • ROM: .text -32 B (-0.0%, 91,404 B / 2,097,152 B, total: 4% used)

s698pm-dkit

  • Code: .text +128 B (+0.0%, 389,072 B)

stm32-nucleo-f103rb

  • flash: .text -24 B (-0.1%, 34,796 B / 131,072 B, total: 27% used)

No memory changes detected for:


Catch memory regressions in CI with MemBrowse. Free for open source.

@Fix-Point
Fix-Point force-pushed the nuttx-seqlock-spinlock-sync2 branch from 21f29a0 to 2eabe5e Compare November 2, 2026 09:31
Comment thread include/nuttx/spinlock_type.h Resolved
Comment thread include/nuttx/spinlock.h Resolved
Comment thread include/nuttx/spinlock.h Resolved
Comment thread include/nuttx/spinlock.h Resolved
Comment thread include/nuttx/spinlock.h Resolved
Comment thread include/nuttx/spinlock.h Resolved
Comment thread include/nuttx/irq.h Resolved
@Fix-Point
Fix-Point force-pushed the nuttx-seqlock-spinlock-sync2 branch 2 times, most recently from 531f176 to 5d57a8b Compare November 2, 2026 12:27
@github-actions github-actions Bot added Area: OS Components OS Components issues Size: M The size of the change in this PR is medium and removed Area: Build system Size: L The size of the change in this PR is large Board: arm Board: z80 labels Nov 2, 2026
Comment thread include/nuttx/spinlock.h Resolved
Fix-Point and others added 5 commits November 4, 2026 09:28
This commit added compiler_assume hint for rspinlock to do
more aggresive optimization.

Assisted-By: mimo-v2.6-pro
Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
RSPINLOCK_COUNT(old_val + 1u) expands to
((uint32_t)(old_val + 1U) & 0xffffU) <= 0xffff which is always true,
making the DEBUGASSERT ineffective.

Change to RSPINLOCK_COUNT(old_val) + 1u so the check correctly validates
that the 16-bit count field will not overflow when incremented.

Assisted-By: mimo-v2.6-pro
Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
Spinlock helpers (spin_lock_notrace, rspin_lock_notrace, rspin_trylock,
rspin_unlock_notrace, read_lock, read_trylock, write_lock) are always
force-inlined today, which bloats every call site on small targets.

disabling it emits a single callable copy of each helper from
irq_spinlock.c, trading a function-call overhead for reduced code size.

When CONFIG_SPINLOCK_INLINE is disabled, irq_spinlock.c defines
SPINLOCK_INLINE as empty and forces CONFIG_SPINLOCK_INLINE on, causing
the header bodies to compile as ordinary (non-static-inline) definitions.

Additionally:
- Inline read_lock_irqsave/read_unlock_irqrestore/write_lock_irqsave/
  write_unlock_irqrestore in the header (trivial wrappers, previously
  extern in irq_spinlock.c) to avoid call overhead for simple
  irq_save + lock sequences.
- Fix rspin_lock_is_hold to only save/restore IRQs under CONFIG_SPINLOCK,
  avoiding unnecessary irq_save on UP builds.

Size reduction: 1400 bytes on a TriCore flat build with the option
disabled.

Assisted-By: mimo-v2.6-pro
Signed-off-by: hujun5 <hujun5@xiaomi.com>
rspin_trylock() has three branches:
1. Lock owned by this CPU  -> ret = true
2. Lock free (old_val == 0) -> ret = CAS result
3. Lock owned by other CPU -> ret is uninitialized

Branch 3 is reachable when another CPU holds the lock, but ret
is never assigned in this path. This causes undefined behavior
and a compile error with clang -Wsometimes-uninitialized.

The bug was introduced in commit 7133388 ("spinlock: Improve
the performance of rspinlock") which refactored rspin_trylock and
changed "bool ret = false" to "bool ret", losing the default
initialization. The paired function rspin_unlock() in the same
commit correctly kept "bool ret = false", confirming this was an
oversight rather than a deliberate optimization.

Fix by restoring the "= false" initializer, which is the correct
return value for trylock failure (lock held by another CPU).

Assisted-By: mimo-v2.6-pro
Signed-off-by: pengxianghao <pengxianghao@xiaomi.com>
Add ARM Wait For Event (WFE) and Send Event (SEV) instructions to spinlock
implementation to reduce CPU contention and prevent livelock issues:

WFE/SEV semantics:
- For CAS-based locks, WFE is called only when lock is actually held,
  not on STREX failure (which can happen due to contention even when
  lock is free).
- SEV is called after releasing lock to wake waiting CPUs from WFE state
- DSB is added before SEV to ensure memory is written

This optimization reduces CPU utilization and power consumption during lock
contention while maintaining backward compatibility.

Assisted-By: mimo-v2.6-pro
Signed-off-by: xuxingliang <xuxingliang@xiaomi.com>
UP_SEV() is empty on RISC-V, x86_64, Xtensa and sim, but UP_DSB() is
fence iorw,iorw on RISC-V and mfence on x86_64, so every spinlock
release paid a full memory barrier that only the ARM WFE/SEV lock
sequence needs.

Move the DSB into the UP_SEV() definitions of the ARM profiles whose
WFE waiters rely on SEV (armv7-a, armv7-r, armv8-r, the generic ARM
fallback used by Cortex-M, and arm64) and drop the unconditional
UP_DSB() calls from the spinlock release paths.  SEV is not a memory
access and is not subject to memory ordering, so a waiter may observe
the event before the lock release store becomes visible, re-read the
stale lock and sleep again with the event already consumed (missed
wakeup).  DSB makes the store visible before SEV.  Exception: a waiter
sleeping with an exclusive monitor armed wakes on the monitor clear
from the store itself and needs neither SEV nor DSB.  See "Use of Wait
For Event (WFE) and Send Event (SEV) with Locks" in the Barrier Litmus
Tests appendix of ARM DDI 0406C:
https://support.arm.com/documentation/ddi0406/c/Appendices/Barrier-Litmus-Tests/Exclusive-accesses-and-barriers/Use-of-Wait-For-Event--WFE--and-Send-Event--SEV--with-Locks?lang=en

Assisted-By: mimo-v2.6-pro
Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
@Fix-Point
Fix-Point force-pushed the nuttx-seqlock-spinlock-sync2 branch from e02fce1 to 93e055d Compare November 4, 2026 02:17
@github-actions github-actions Bot added Arch: arm64 Issues related to ARM64 (64-bit) architecture Size: L The size of the change in this PR is large and removed Size: M The size of the change in this PR is medium labels Nov 4, 2026
WFE and SEV are baseline instructions in ARMv7-A/R and ARMv8-R.
ARCH_ARMV7A already selects ARM_HAVE_WFE_SEV, but ARCH_ARMV7R and
ARCH_ARMV8R did not, so the spinlock WFE/SEV waiting was inactive
there and UP_WFE() fell back to an empty macro.

Select ARM_HAVE_WFE_SEV for ARCH_ARMV7R and ARCH_ARMV8R as well, so
the common UP_WFE()/UP_SEV() definitions in arch/arm/include/arch.h
cover all of these profiles, and remove the per-profile UP_SEV()
overrides from the armv7-a/armv7-r/armv8-r barriers.h along with the
now unused arm_sev() helpers.  This leaves a single UP_SEV()
definition per arch, keeping the required DSB before SEV.

Assisted-By: mimo-v2.6-pro
Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
@github-actions github-actions Bot added Size: M The size of the change in this PR is medium and removed Size: L The size of the change in this PR is large labels Nov 4, 2026
@Fix-Point
Fix-Point force-pushed the nuttx-seqlock-spinlock-sync2 branch 2 times, most recently from ef5c1dc to c4e3890 Compare November 4, 2026 08:45
xiaoxiang781216
xiaoxiang781216 previously approved these changes Nov 4, 2026

@casaroli casaroli left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Speed note, not a blocker. ostest spinlock average throughput, op/s, on qemu-armv8a:nsh_smp with 4 CPUs under HVF on an Apple core, one run each:

threads, lock master this PR merged with master
1, spinlock 139 M 17.3 M
1, rspinlock 108 M 17.1 M
2, spinlock 33.4 M 5.7 M
4, spinlock 11.4 M 2.4 M
4, rspinlock 8.7 M 2.9 M

The host was running other builds during these runs, so this comparison is inconclusive. On arm64 the unlock now has DSB and SEV, which master does not have. A measurement on an idle host or on real arm64 hardware is needed to say what this costs.

@casaroli casaroli left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have concerns about the performance of this change: on arm64 every unlock now runs DSB and SEV, and no option turns them off. Our numbers above are inconclusive, so we will measure first, on an idle host, before we approve.

@casaroli casaroli left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Measured on a quiet host: qemu-armv8a:nsh_smp, 4 CPUs, HVF on an Apple core, ostest spinlock test, median of 3 runs, M op/s. This replaces my earlier numbers.

threads, lock master this PR no WFE/SEV in spinlock.h SEV without DSB
1, spinlock 155.9 11.3 155.2 115.8
1, rspinlock 153.6 11.8 155.7 114.2
2, spinlock 48.8 8.9 44.3 40.4
2, rspinlock 49.5 9.0 41.1 30.9
3, spinlock 30.6 4.8 29.3 21.9
3, rspinlock 28.7 5.1 25.1 18.1
4, spinlock 26.9 3.5 24.6 18.5
4, rspinlock 21.7 4.0 22.0 13.5

The last column is for measurement only; it is not correct code. Most of the cost is the DSB before SEV in every unlock. This is one platform and a lock/unlock loop.

Fix: on arm64, wait with the exclusive monitor armed, the exception that 93e055d describes, so that the unlock needs neither SEV nor DSB; or make WFE/SEV an option, off by default on arm64.

@Fix-Point

Copy link
Copy Markdown
Contributor Author

Measured on a quiet host: qemu-armv8a:nsh_smp, 4 CPUs, HVF on an Apple core, ostest spinlock test, median of 3 runs, M op/s. This replaces my earlier numbers.

threads, lock master this PR no WFE/SEV in spinlock.h SEV without DSB
1, spinlock 155.9 11.3 155.2 115.8
1, rspinlock 153.6 11.8 155.7 114.2
2, spinlock 48.8 8.9 44.3 40.4
2, rspinlock 49.5 9.0 41.1 30.9
3, spinlock 30.6 4.8 29.3 21.9
3, rspinlock 28.7 5.1 25.1 18.1
4, spinlock 26.9 3.5 24.6 18.5
4, rspinlock 21.7 4.0 22.0 13.5
The last column is for measurement only; it is not correct code. Most of the cost is the DSB before SEV in every unlock. This is one platform and a lock/unlock loop.

Fix: on arm64, wait with the exclusive monitor armed, the exception that 93e055d describes, so that the unlock needs neither SEV nor DSB; or make WFE/SEV an option, off by default on arm64.

Thanks for the numbers — they make it clear the wait policy is a platform trade-off and must be opt-in. We replaced the unconditional WFE/SEV with a configurable lock wait policy, in two new commits:

  1. sched/Kconfig: add spinlock wait policy choice — a Kconfig choice between busy wait (CONFIG_SPINLOCK_NOPWAIT) and WFE/SEV wait (CONFIG_SPINLOCK_WFESEV), with SPINLOCK_WAIT()/SPINLOCK_WAKE() as the single policy point. The choice defaults to NOPWAIT; each architecture declares where WFE/SEV waiting pays off by selecting the hidden SPINLOCK_WFESEV_DEFAULT (armv7-a and Intel 64, and the M-profiles when SMP). arm64 does not select it.

  2. spinlock: route lock waiting through SPINLOCK_WAIT/SPINLOCK_WAKE — the lock paths call the policy macros instead of UP_WFE()/UP_SEV() directly.

This is essentially your "make WFE/SEV an option, off by default on arm64", generalized. On arm64 the default NOPWAIT restores the master unlock path (plain release store, no DSB/SEV), so the regression in your table is gone — the "no WFE/SEV in spinlock.h" column is what to expect. On Intel 64, WFESEV is only PAUSE in the wait loop with an empty wake event, so unlock stays free; on Arm v7-A the DSB before SEV remains folded into UP_SEV() per ARM DDI 0406C ("Use of WFE and SEV with Locks").

@github-actions github-actions Bot added Arch: x86_64 Issues related to the x86_64 architecture Size: L The size of the change in this PR is large and removed Size: M The size of the change in this PR is medium labels Nov 5, 2026
The WFE/SEV lock waiting made every unlock pay for a DSB before SEV,
a full barrier on the unlock hot path (measured 155.9 -> 11.3 M
lock/unlock ops/s single-threaded on qemu-armv8a), and no platform
wants that cost unconditionally: armv7a and SMP Cortex-M prefer the
power saving, Intel 64 only wants PAUSE in the wait loop, and arm64,
RISC-V and realtime profiles prefer the raw throughput.

Add a choice between busy wait (NOPWAIT) and WFE/SEV wait (WFESEV)
with SPINLOCK_WAIT()/SPINLOCK_WAKE() as the single policy point.  The
choice defaults to NOPWAIT; each architecture declares where WFE/SEV
waiting pays off by selecting SPINLOCK_WFESEV_DEFAULT when SMP
(armv7-a, Intel 64 and the M-profiles).  This commit adds the
configuration and the macros only; the lock paths switch to them in
the next commit.

Assisted-By: mimo-v2.6-pro
Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
Replace the direct UP_WFE()/UP_SEV() calls in the spinlock paths with
the policy macros.  Under the default NOPWAIT policy the unlock path
becomes a plain release store again on arm64, RISC-V, Xtensa, sim and
the realtime profiles, restoring master throughput; armv7a, Intel 64
(PAUSE only) and SMP Cortex-M keep the WFE/SEV waiting via WFESEV.

Assisted-By: mimo-v2.6-pro
Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
@Fix-Point
Fix-Point force-pushed the nuttx-seqlock-spinlock-sync2 branch from 2a2c427 to 758f22e Compare November 5, 2026 03:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: arm Issues related to ARM (32-bit) architecture Arch: arm64 Issues related to ARM64 (64-bit) architecture Arch: x86_64 Issues related to the x86_64 architecture Area: OS Components OS Components issues Size: L The size of the change in this PR is large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants