@colinw
You are right, that's another workarounds for the missing reschedule method. But still a workarounds.
@salass00
This might work. Depends on why you are calling IExec->Reschedule() from an application?.
My personal meaning is, if we take a wider look at where IExec->Reschedule is used and how, I think 99%
of the usage is not correct, and the remaining 1% usage is probably just for os/kernel related stuff.
Let me explain why i think that 99% of the usage is wrong. First of all from an application point of view,
what to you gain from a call to IExec->Reschedule()? BTW i couldn't find any documentation about it in any
of the available SDKs. So i assume it does something similar as the side effect of calling SetTaskPri;
Quote:
A reschedule is performed, and a context switch may result.
The reschedule per se is transparent for the calling application, but the optional context switch can be
misused to synchronized task/process. Like the implementation of
pthread_once method of the gcc compiler at
https://github.com/sba1/adtools/ uses it:
int __gthread_once (__gthread_once_t *__once, void (*__func) (void)) {
__internal_gthread_once_t *once = (__internal_gthread_once_t *)__once;
if (__once == NULL || __func == NULL)
return EINVAL;
if (__atomic_load_1(&once->u.i.done, __ATOMIC_SEQ_CST))
return 0;
if (!__atomic_test_and_set(&once->u.i.started, __ATOMIC_SEQ_CST)) {
/* Started flag was not set so call func now */
__func();
/* Remember that we are done now. And make all effects prior to this
* store visible to all the other clients that will read that we are
* actually done.
*/
__atomic_store_1(&once->u.i.done, 1, __ATOMIC_SEQ_CST);
}
else {
while (!__atomic_load_1(&once->u.i.done, __ATOMIC_SEQ_CST)) {
/* Allow the other thread to progress quickly but iexec may be not available */
struct ExecBase *SysBase = *(struct ExecBase **)4;
struct ExecIFace *ie = (struct ExecIFace *)SysBase->MainInterface;
ie->Reschedule();
}
}
return 0;
}
To understand what it does the
man page of pthread_once might help. It ensures that the __func method gets only called once,
regardless how many tasks/processes/threads simultaneously or each after another calls pthread_once. The trickiest part of
the implementation is if more than one task/process/thread calls pthread_once simultaneously, or better said, if task/process/thread A
still executes __func and during that additional tasks/processes/threads calls pthread_once. Because currently with one CPU core no real
multitasking is possible, one of the additional tasks/processes/threads would starve task/process/thread A. To avoid that the author
used IExec->Reschedule to give process A time on the CPU. Mainly relaying on that the optional context switch is performed, and A gets
process time on the CPU. With lowering the task pri it makes this even more likely, especially if A has a higher priority.
If in a future the AmigaOS kernel can utilize multiple CPU/Cores, the solution could break. With missing documentation of
IExec->Reschedule there are a lot of question raising in my head for a future multi core system, what a call of
Reschedule will result in...
a) just reschedule the tasks on the core where my calling tasks run?
b) all cores?
c) any other core expect the core my task runs on
d) randomly one core of all available
Some of them don't sound reasonable, but if the behavior isn't a/b you can build scenarios where the implementation above won't work.
And i might think a solution b wouldn't be good to overall performance of the os on a multiple core setup.
For the above implementation a better solution for replacing IExec->Reschedule would be to have the calling task to go to "sleep". But
there isn't a sleep function in Exec, just the Delay method in DOS, which again might not be callable if the calling task isn't a Process
or at least hasn't setup a MsgPort as mention on in the AutoDoc of DOS.
And for me i think it is correct that the SDK doesn't publicly offer the Reschedule function. It should be use by normal applications.
BTW on the pthread branch of afxgroup clib2 there is different implementation of
pthread_once, which don't use a sleep of reschedule
kind of mechanism to handle the task/.. synchronization. Instead it's solution builds upon a look. Which in my opinion is even nicer,
because of no looping (and the threads gets put to sleep and just gets wake up from the os
than they can continue there work.