Apparent inconsistency in eventlog thread stop status codes
In the ghc eventlog, the `STOP_THREAD` event has status codes. There are three places where these codes exist and ought to be consistent:
* the ghc documentation (`docs/users_guide/eventlog-formats.rst`)
* the eventlog parser in the `ghc-events` package
* the ghc rts code that emits the codes
Unfortunately these are not consistent.
The `ghc-events` package has this:
```
mkStopStatus :: RawThreadStopStatus -> ThreadStopStatus
mkStopStatus n = case n of
0 -> NoStatus
1 -> HeapOverflow
2 -> StackOverflow
3 -> ThreadYielding
4 -> ThreadBlocked
5 -> ThreadFinished
6 -> ForeignCall
7 -> BlockedOnMVar
8 -> BlockedOnBlackHole
9 -> BlockedOnRead
10 -> BlockedOnWrite
11 -> BlockedOnDelay
12 -> BlockedOnSTM
13 -> BlockedOnDoProc
14 -> BlockedOnCCall
15 -> BlockedOnCCall_NoUnblockExc
16 -> BlockedOnMsgThrowTo
17 -> ThreadMigrating
18 -> BlockedOnMsgGlobalise
19 -> NoStatus -- yeuch... this one does not actually exist in GHC event logs
20 -> BlockedOnMVarRead -- since GHC-7.8.3
```
while the ghc docs `docs/users_guide/eventlog-formats.rst` has this
```
* 1: HeapOverflow
* 2: StackOverflow
* 3: ThreadYielding
* 4: ThreadBlocked
* 5: ThreadFinished
* 6: ForeignCall
* 7: BlockedOnMVar
* 8: BlockedOnBlackHole
* 9: BlockedOnRead
* 10: BlockedOnWrite
* 11: BlockedOnDelay
* 12: BlockedOnSTM
* 13: BlockedOnDoProc
* 16: BlockedOnMsgThrowTo
* 20: BlockedOnMVarRead
```
These two are basically consistent with each other. The difference being that the user guide does not define 14,15 and 17,18,19.
Unfortunately these two sources are _not_ consistent with the implementation. The implementation has two ways to emit the codes, directly (for codes 1 to 5) and then the remainder are the `why_blocked` codes, which are converted into the eventlog thread stop codes by adding 6:
```
uint16_t why_blocked = ACQUIRE_LOAD(&t->why_blocked);
if (why_blocked == BlockedOnBlackHole) {
StgTSO *owner = blackHoleOwner(t->block_info.bh->bh);
traceEventStopThread(cap, t, t->why_blocked + 6,
owner != NULL ? owner->id : 0);
} else {
traceEventStopThread(cap, t, t->why_blocked + 6, 0);
}
```
and the `why_blocked` codes are defined like so:
```
#define NotBlocked 0
#define BlockedOnMVar 1
#define BlockedOnMVarRead 14 /* TODO: renumber me, see #9003 */
#define BlockedOnBlackHole 2
#define BlockedOnRead 3
#define BlockedOnWrite 4
#define BlockedOnDelay 5
#define BlockedOnSTM 6
/* Win32 only: */
#define BlockedOnDoProc 7
/* Only relevant for THREADED_RTS: */
#define BlockedOnCCall 10
#define BlockedOnCCall_Interruptible 11
/* same as above but permit killing the worker thread */
/* Involved in a message sent to tso->msg_cap */
#define BlockedOnMsgThrowTo 12
/* The thread is not on any run queues, but can be woken up
by tryWakeupThread() */
#define ThreadMigrating 13
```
So lets line this all up in a table...
| Event name | ghc-events | ghc docs | `why_blocked` | `why_blocked + 6` |
| ------------------ | ---------- | -------- | ------------- | ----------------- |
| HeapOverflow | 1 | 1 | | |
| StackOverflow | 2 | 2 | | |
| ThreadYielding | 3 | 3 | | |
| ThreadBlocked | 4 | 4 | | |
| ThreadFinished | 5 | 5 | | |
| ForeignCall | 6 | 6 | | |
| BlockedOnMVar | 7 | 7 | 1 | 7 |
| BlockedOnBlackHole | 8 | 8 | 2 | 8 |
| BlockedOnRead | 9 | 9 | 3 | 9 |
| BlockedOnWrite | 10 | 10 | 4 | 10 |
| BlockedOnDelay | 11 | 11 | 5 | 11 |
| BlockedOnSTM | 12 | 12 | 6 | 12 |
| BlockedOnDoProc | 13 | 13 | 7 | 13 |
| BlockedOnCCall | 14 | | 10 | 16 |
| BlockedOnCCall_In..| 15 | | 11 | 17 |
| BlockedOnMsgThrowTo| 16 | 16 | 12 | 18 |
| ThreadMigrating | 17 | | 13 | 19 |
| BlockedOnMsgGloba..| 18 | | | |
| NoStatus | 19 | | | |
| BlockedOnMVarRead | 20 | 20 | 14 | 20 |
So everything is consistent between the sources, up to `BlockedOnDoProc` and then it's all inconsistent, until `BlockedOnMVarRead` which is consistent again.
A few notes:
* The reason for 14 & 15 missing from the docs is probably this: while they _are_ `why_blocked` status codes used in the RTS, they will never be emitted to the eventlog, instead the RTS will always emit code 6 for this.
* `BlockedOnMsgGlobalise` is a bit of mystery. It was added into `ghc-events` in 2010 (by Simon M) but it has never existed in ghc's master branch. It's plausible that Simon was working on his local GC implementation at the time and simply copied the codes from that branch, and then that message and blocked status never got merged to master.
* The `NoStatus` is just an in-fill used in `ghc-events` and is documented there as such.
* GHC does not define `why_blocked` constants 8 and 9, which is why it does not have (+6) status numbers 14 & 15.
* The current GHC values for the `why_blocked` constants seems to have settled down in 2010
* GHC codes 8 & 9 were historically for `BlockedOnGA` and `BlockedOnGA_NoSend` and were marked `/* Only relevant for PAR: */`
So it looks like codes `BlockedOnMsgThrowTo` and `ThreadMigrating` have been simply wrong in `ghc-events` for 16 years. And although `ghc-events` also has `BlockedOnCCall` and `BlockedOnCCall_NoUnblockExc` wrong, this has never mattered because they are never emitted.
If this analysis is right, we should fix the ghc user guide docs, and file an issue for `ghc-events`.
issue