Improve behaviour when used with RTSupport threads

Two of the locking data types - mutex_t and spinrw_t - offer a
lock-with-sleep function. These can cause the current thread to sleep until
another thread releases the lock. Sleeping is achieved using OS_UpCall 6, and
so supports thread suspension by either TaskWindow or RTSupport.

This is usually fine, but RTSupport, unlike TaskWindow, permits threads to
be assigned differing priority levels. Thus, if a lock is held by a
low-priority thread when a high-priority thread attempts to lock it, the
low-priority thread continues to run (this is a common feature of
priority-based threading systems known as priority inversion). This is
unavoidable in some situations, but ideally the high-priority thread should
be resumed as soon as the shared resource (in this case the lock) is
released by the low-priority thread. Previously, there was no mechanism to
achieve this with either of these two lock types.

One challenge is to achieve this without making the unlock functions
unnecessarily slow in the common case where there is no higher-priority
thread to resume. This is achieved in two ways:

1) Yielding is performed using RT_Yield to explicitly rescan pollwords for
   RTSupport threads only. Since TaskWindow threads are all implicitly of
   identical priority, we avoid using an OS_UpCall 6 yield, which would
   cause all TaskWindow pollwords to be rescanned as well.

2) An internal flag inside the lock struct is used to remember whether any
   other threads attempted to lock it when it was already locked, and a yield
   is only performed when unlocking if this indicates there is (or might be)
   another thread waiting.

The situation is complicated by the fact that (despite what the SWI docs say)
RT_Yield can cause IRQs to trigger even if the caller has them disabled. This
can however be inferred from the entry conditions of RTSupport callback
routines, which usually have IRQs enabled, so if any IRQ-enabled routine is
pending when we call RT_Yield, IRQs will become enabled. This is a problem
because if the calling thread also holds non-re-entrant locks (e.g. a
spinlock) then we defeat those locks by pre-empting the thread in this way.
To deal with this, we check that IRQs are enabled prior to calling RT_Yield,
even though this will also discard many cases where a yield would have been
desirable. A future enhancement would be to maintain a thread-local flag, and
trigger RT_Yield when the outermost IRQ-disabling lock is released (even if
that lock type wouldn't ordinarily cause other threads to sleep) but this
presumes thread-local storage, which is not yet implemented for RTSupport.

More sophisticated schemes are possible, such as by comparing the relative
priorities of the lock holder and waiter, but these introduce additional
overheads into the lock and unlock functions, so unless and until it becomes
clear that they are required, they have not been implemented.
18 jobs for !1 with FixPriorityInversion in 3 minutes and 9 seconds (queued for 30 seconds)
detached
Status Job ID Name Coverage
  Static Analysis
failed #40390
cross allowed to fail
cppcheck

00:00:04

passed #40381
cross
gitattributes

00:00:01

passed #40382
cross
gitignore

00:00:01

passed #40385
cross
head_log

00:00:01

passed #40388
cross
head_whitesp

00:00:00

passed #40383
cross
license

00:00:01

passed #40387
cross
makefile

00:00:00

passed #40386
cross
merge_log

00:00:00

failed #40389
cross allowed to fail
merge_whitesp

00:00:00

passed #40384
cross
versionnum

00:00:00

 
  Disc
failed #40391
cross allowed to fail
disc_Disc

00:00:27

 
  Rom
failed #40392
cross allowed to fail
rom_BCM2835

00:00:24

failed #40397
cross allowed to fail
rom_iMx6

00:00:24

failed #40393
cross allowed to fail
rom_OMAP3

00:00:24

failed #40394
cross allowed to fail
rom_OMAP4

00:00:24

failed #40395
cross allowed to fail
rom_OMAP5

00:00:24

failed #40396
cross allowed to fail
rom_Titanium

00:00:24

 
  Cleanup
passed #40398
cross
cleanup

00:00:01

 
Name Stage Failure
failed
rom_iMx6 Rom
Error running make export (hdrs) on module 'HAL_iMx6'.
Error running make export (hdrs) on module 'FileCore'.
Error running make export (hdrs) on module 'ADFS'.
Error running make export (hdrs) on module 'RamFS'.
Error running make export (hdrs) on module 'SCSIFS'.
Error running make export (hdrs) on module 'SDFS'.
------------------------------------------------------------------------------
Cleaning up project directory and file based variables
ERROR: Job failed: exit status 1

failed
rom_Titanium Rom
Batched errors...
Error running make export (hdrs) on module 'FileCore'.
Error running make export (hdrs) on module 'ADFS4'.
Error running make export (hdrs) on module 'RamFS'.
Error running make export (hdrs) on module 'SCSIFS'.
Error running make export (hdrs) on module 'SDFS'.
------------------------------------------------------------------------------
Cleaning up project directory and file based variables
ERROR: Job failed: exit status 1

failed
rom_OMAP5 Rom
Batched errors...
Error running make export (hdrs) on module 'FileCore'.
Error running make export (hdrs) on module 'ADFS4'.
Error running make export (hdrs) on module 'RamFS'.
Error running make export (hdrs) on module 'SCSIFS'.
Error running make export (hdrs) on module 'SDFS'.
------------------------------------------------------------------------------
Cleaning up project directory and file based variables
ERROR: Job failed: exit status 1

failed
rom_OMAP4 Rom
Error running make export (hdrs) on module 'HAL_OMAP4'.
Error running make export (hdrs) on module 'FileCore'.
Error running make export (hdrs) on module 'ADFS'.
Error running make export (hdrs) on module 'RamFS'.
Error running make export (hdrs) on module 'SCSIFS'.
Error running make export (hdrs) on module 'SDFS'.
------------------------------------------------------------------------------
Cleaning up project directory and file based variables
ERROR: Job failed: exit status 1

failed
rom_OMAP3 Rom
Batched errors...
Error running make export (hdrs) on module 'FileCore'.
Error running make export (hdrs) on module 'ADFS'.
Error running make export (hdrs) on module 'RamFS'.
Error running make export (hdrs) on module 'SCSIFS'.
Error running make export (hdrs) on module 'SDFS'.
------------------------------------------------------------------------------
Cleaning up project directory and file based variables
ERROR: Job failed: exit status 1

failed
rom_BCM2835 Rom
Error running make export (hdrs) on module 'HAL_BCM2835'.
Error running make export (hdrs) on module 'FileCore'.
Error running make export (hdrs) on module 'ADFS'.
Error running make export (hdrs) on module 'RamFS'.
Error running make export (hdrs) on module 'SCSIFS'.
Error running make export (hdrs) on module 'SDFS'.
------------------------------------------------------------------------------
Cleaning up project directory and file based variables
ERROR: Job failed: exit status 1

failed
disc_Disc Disc
Error running make export (hdrs) on module 'PDumperE2'.
Error running make export (hdrs) on module 'PDumperIW'.
Error running make export (hdrs) on module 'PDumperLJ'.
Error running make export (hdrs) on module 'DesktopBoot'.
Error running make export (hdrs) on module 'PatchesPatch'.
Error running make export (hdrs) on module 'ChangeFSI'.
------------------------------------------------------------------------------
Cleaning up project directory and file based variables
ERROR: Job failed: exit status 1

failed
cppcheck Static Analysis

^
objs/mutex.c:72:0: style: The function 'mutex_unlock' is never used. [unusedFunction]

^
nofile:0:0: information: Unmatched suppression: purgedConfiguration [unmatchedSuppression]

Cleaning up project directory and file based variables
ERROR: Job failed: exit status 1

failed
merge_whitesp Static Analysis
Executing "step_script" stage of the job script
$ git remote show | grep target > /dev/null && git remote remove target || true; git remote add -t $CI_MERGE_REQUEST_TARGET_BRANCH_NAME -f target $CI_MERGE_REQUEST_PROJECT_URL.git; awk ' ''BEGIN { '' result = 0; '' cmd = "git diff -b -U0 target/'$CI_MERGE_REQUEST_TARGET_BRANCH_NAME' HEAD"; '' while ((cmd | getline) > 0) { '' if ($1 == "+++") '' file = gensub(/^b\//, "", "1", $2); '' else if ($1 == "@@") '' line = gensub(/+([0-9]+).*/, "\\1", "1", $3); '' else if ($0 ~ /^+/) '' change[file][line++]; '' } '' close(cmd); '' cmd = "git diff -U0 target/'$CI_MERGE_REQUEST_TARGET_BRANCH_NAME' HEAD"; '' while ((cmd | getline) > 0) { '' if ($1 == "+++") { '' file = gensub(/^b\//, "", "1", $2); '' change[file]["dummy"] '' } else if ($1 == "@@") '' line = gensub(/+([0-9]+).*/, "\\1", "1", $3); '' else if ($0 ~ /^+/) { '' sub(/^+/, ""); '' if ($0 ~ /( +\t|[\t ]$)/) { '' print file " line " line " adds whitespace error"; '' result = 1 '' } else if (!(line in change[file])) { '' print file " line " line " only removes whitespace error"; '' result = 1 '' } '' ++line '' } '' } '' close(cmd) ''} ''END { exit result }'
Updating target
From https://gitlab.riscosopen.org/RiscOS/Sources/Lib/SyncLib
* [new branch] master -> target/master
VersionNum line 8 only removes whitespace error
s/spinrw line 59 only removes whitespace error
Cleaning up project directory and file based variables
ERROR: Job failed: exit status 1