Also, the documentation says that interrupts are disabled in S locked state, but there is code like the following which works. So.are interrupts disabled or not? [I know they are not, I'm just trying to come up with a coherent understanding of the lock states .... And to reconcile language in the documentation]
Thread:
ChSysLock
chThdSuspendS
...
ISR
ChSysLockISR
chThdResumeI
...
context switch observed inside S-locked state Topic is solved
- Giovanni
- Site Admin
- Posts: 14457
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: context switch observed inside S-locked state
Hi Faisal,
The S state is where context switch happens, it is meant to happen in that state if you call an S function (S functions are exactly those functions that can do a context switch inside).
Everywhere in the kernel you will see something like this:
The critical section does not guarantee atomicity across the call to S-function. Interrupt are indeed disabled but could be serviced in there "on the other side" of the context switch, the other thread will call chSysUnlock() after exiting from its own S-function.
You should see this as:
If you need atomicity then do:
This delays the context switch to the point where you want it to happen, you can also call multiple "I" functions and then reschedule atomically in one point (common use case, imagine you want to signal 2 semaphores atomically).
Giovanni
The S state is where context switch happens, it is meant to happen in that state if you call an S function (S functions are exactly those functions that can do a context switch inside).
Everywhere in the kernel you will see something like this:
Code: Select all
chSysLock();
...
chSomethingS();
...
chSysUnlock();
The critical section does not guarantee atomicity across the call to S-function. Interrupt are indeed disabled but could be serviced in there "on the other side" of the context switch, the other thread will call chSysUnlock() after exiting from its own S-function.
You should see this as:
Code: Select all
chSysLock();
...
chSysUnlock();
chSomething();
chSysLock();
...
chSysUnlock();
If you need atomicity then do:
Code: Select all
chSysLock();
...
chSomethingI();
...
chSomethingI();
...
chSchRescheduleS();
chSysUnlock();
This delays the context switch to the point where you want it to happen, you can also call multiple "I" functions and then reschedule atomically in one point (common use case, imagine you want to signal 2 semaphores atomically).
Giovanni
Re: context switch observed inside S-locked state
So, given that - do you think the documentation needs to elaborate some more on what S-locked means?
So they are disabled until an S class API call is made. As you explained, to imagine it as:
So interrupts really truly are disabled after chSysLock() until the first call to S class function? At what point are interrupts enabled again, and what type of S class functions will result in interrupts being enabled? Knowing the side effects of system calls with regards to when interrupts are enabled/disabled should be clear (they aren't crystal clear in my head, I have to rediscover this every now and then, and forget eventually).
S-Locked. Kernel locked and regular interrupt sources disabled. Fast interrupt sources are enabled. S-Class and I-Class APIs are invokable in this state.
So they are disabled until an S class API call is made. As you explained, to imagine it as:
Code: Select all
chSysLock();
...
chSysUnlock(); // imagined
chSomething();
chSysLock(); // imagined
...
chSysUnlock();
So interrupts really truly are disabled after chSysLock() until the first call to S class function? At what point are interrupts enabled again, and what type of S class functions will result in interrupts being enabled? Knowing the side effects of system calls with regards to when interrupts are enabled/disabled should be clear (they aren't crystal clear in my head, I have to rediscover this every now and then, and forget eventually).
- Giovanni
- Site Admin
- Posts: 14457
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: context switch observed inside S-locked state
Interrupts are not enabled by the S function but the function performs a context switch, it is the OTHER thread re-enabling interrupts, the context switch is always performed from a critical section so after a switch an unlock follows on the other side.
Giovanni
Giovanni
- sabdulqadir
- Posts: 49
- Joined: Fri Mar 23, 2018 7:29 pm
- Has thanked: 13 times
- Been thanked: 4 times
Re: context switch observed inside S-locked state
Giovanni wrote:I-class functions never perform a context switch, s-class can do that.
...
The ambiguity is that chSchRescheduleS() could not be required depending on which I-class functions you are using, it does not hurt anyway. In general, those I-class functions that can wakeup other threads require the final reschedule.
See this article: http://chibios.org/dokuwiki/doku.php?id ... :kb:atomic
Giovanni
Hi Giovanni,
Can you update the link here?
Thanks,
AQ
- Giovanni
- Site Admin
- Posts: 14457
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
- sabdulqadir
- Posts: 49
- Joined: Fri Mar 23, 2018 7:29 pm
- Has thanked: 13 times
- Been thanked: 4 times
Re: context switch observed inside S-locked state
Hi Giovanni,
Thanks for the input here. This does sound confusing. Specially when the documentation does not make it any clearer. Consider this example:
Thread:
ChSysLock()
chThdSuspendTimeoutS()
ChSysUnlock()
It seems that the thread locks the system (no interrupts) and then goes to sleep. Even if we assume that rescheduling would happen and next ready thread would take over, I am still unsure who unlocks the system.
Would the next ready thread have to explicitly unlock the system?
Thanks,
AQ
Thanks for the input here. This does sound confusing. Specially when the documentation does not make it any clearer. Consider this example:
Thread:
ChSysLock()
chThdSuspendTimeoutS()
ChSysUnlock()
It seems that the thread locks the system (no interrupts) and then goes to sleep. Even if we assume that rescheduling would happen and next ready thread would take over, I am still unsure who unlocks the system.
Would the next ready thread have to explicitly unlock the system?
Thanks,
AQ
Re: context switch observed inside S-locked state
sabdulqadir wrote:Hi Giovanni,
Thanks for the input here. This does sound confusing. Specially when the documentation does not make it any clearer. Consider this example:
Thread:
ChSysLock()
chThdSuspendTimeoutS()
ChSysUnlock()
It seems that the thread locks the system (no interrupts) and then goes to sleep. Even if we assume that rescheduling would happen and next ready thread would take over, I am still unsure who unlocks the system.
Would the next ready thread have to explicitly unlock the system?
Thanks,
AQ
So, let's expand this the way Giovanni did previously:
Code: Select all
ChSysLock()
ChSysUnlock() /* Implicit */
chSysLock() /* Implicit */
chThdSuspendTimeoutS()
/* Port level context switch to idle thread if that is the only thread ready to run */
chSysUnlock() /* Implicit */
chSysLock() /* Implicit */
ChSysUnlock()
Since chThdSuspendTimeoutS() is an S-class API, it could (and does in this case) re-run the scheduler and context switches if necessary. In this case, since the thread is going to sleep, it will context switch to the next thread which is ready to run with the highest priority. Once the context switch occurs, interrupts are re-enabled (unless the context switch occurs and we happen to end up in the S-locked state in another context which is ready to run). If no thread is ready to run, it will switch to the idle thread because it is always ready to run.
Re: context switch observed inside S-locked state
This helps: Get the notion out of your head that the "Lock" ind ChSysLock() means that you are establishing a critical zone as you would in other RTOSes. It's not true that interrupts are completely disabled from your ChSysLock() invocation to your next ChSysUnlock() invocation. S-Class APIs can and will context switch if needed when you invoke them. Once you context switch, the thread that you context switch to now exits "S-Lock" state if necessary and interrupts will be enabled. I said will exit "S-lock" state if necessary, because it's possible that it may not. For example, you context switch to another thread which was already in an S-lock state when it was taken out of the ready queue.
In the above scenario thread 1 will keep pushing objects into the FIFO. As soon as an object is pushed, it will context switch to the higher priority thread 2A that is waiting on the fifo. Thread 2A will process the item, then will go back to waiting on the fifo and a context switch will happen again back to thread 1. And this will repeat. All the while, I believe that interrupts will *not* be enabled. Now, if the higher priority thread were this instead:
... each time the context switch happens from thread 1 to thread 2B, interrupts will be enabled as soon as execution context returns to thread 2B (because it wasn't in a S-lock state when it was pre-emptied/went to sleep).
In order to turn your chSysLock() <-> chSysUnlock() region of code into a true "critical zone" (no interrupts, or scheduler running) you have to be conscious of what you put in there. It's not as simple as do a lock(), then do whatever, then unlock(). S-class API calls can and will reschedule and interrupts could end up being enabled. You will have to look at the documentation/source code for whichever S-class API you intend to use in your S-locked state to figure out if it's possible for a reschedule to happen. To be safe, just don't call any S-class APIs in your S-lock state if you want the guarantee of no interrupts or scheduling. You can use I-class APIs - which are guaranteed not to reschedule. The downside of that is that if the side effects of calling those I-class APIs is that a reschedule should happen (when exiting the S-lock state), you need to explicitly call the scheduler before exiting S-lock state.
Follow the article Giovanni referenced and you'll be golden.
Hope this long winded explanation of basically what's in that article helps. I know I've head to convince myself of this a few times already .
Code: Select all
//Thread 1 (low priority)
ChSysLock();
for (i = 0; i < 10; i++) chFifoSendObjectS();
ChSysUnlock();
//Thread 2A (high priority)
ChSysLock();
while (chFifoReceiveObjectTimeoutS() == MSG_OK);
ChSysUnlock();
In the above scenario thread 1 will keep pushing objects into the FIFO. As soon as an object is pushed, it will context switch to the higher priority thread 2A that is waiting on the fifo. Thread 2A will process the item, then will go back to waiting on the fifo and a context switch will happen again back to thread 1. And this will repeat. All the while, I believe that interrupts will *not* be enabled. Now, if the higher priority thread were this instead:
Code: Select all
// Thread 2B (high priority)
while (chFifoReceiveObjectTimeoutS() == MSG_OK);
... each time the context switch happens from thread 1 to thread 2B, interrupts will be enabled as soon as execution context returns to thread 2B (because it wasn't in a S-lock state when it was pre-emptied/went to sleep).
In order to turn your chSysLock() <-> chSysUnlock() region of code into a true "critical zone" (no interrupts, or scheduler running) you have to be conscious of what you put in there. It's not as simple as do a lock(), then do whatever, then unlock(). S-class API calls can and will reschedule and interrupts could end up being enabled. You will have to look at the documentation/source code for whichever S-class API you intend to use in your S-locked state to figure out if it's possible for a reschedule to happen. To be safe, just don't call any S-class APIs in your S-lock state if you want the guarantee of no interrupts or scheduling. You can use I-class APIs - which are guaranteed not to reschedule. The downside of that is that if the side effects of calling those I-class APIs is that a reschedule should happen (when exiting the S-lock state), you need to explicitly call the scheduler before exiting S-lock state.
Follow the article Giovanni referenced and you'll be golden.
Hope this long winded explanation of basically what's in that article helps. I know I've head to convince myself of this a few times already .
- Giovanni
- Site Admin
- Posts: 14457
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: context switch observed inside S-locked state
I know it is a bit non-obvious, the whole RTOS has been designed around that lock-switch-unlock concept, lock/unlock are not about disabling interrupts, there are enable/suspend/disable for that.
In SMP mode lock/unlock also manage the kernel spinlock because kernel structures are accessed by multiple cores so it becomes lock-do_shared_kernel_things-unlock and it ensures consistency among multiple OS instances.
Giovanni
In SMP mode lock/unlock also manage the kernel spinlock because kernel structures are accessed by multiple cores so it becomes lock-do_shared_kernel_things-unlock and it ensures consistency among multiple OS instances.
Giovanni
Who is online
Users browsing this forum: No registered users and 45 guests