|
418 | 418 | * @c DISABLED states. |
419 | 419 | * |
420 | 420 | * @section q_critical Critical sections |
421 | | -* Since the kernel is non-preemptive, the only critical section that must be |
422 | | -* handled are the shared resources accessed from the ISR context. Perhaps, the |
423 | | -* most obvious way of achieving mutual exclusion is to allow the kernel to |
424 | | -* disable interrupts before it enters their critical section and then, enable |
425 | | -* interrupts after it leaves its critical section. |
426 | | -* |
427 | | -* By disabling interrupts, the CPU will be unable to change the current context. |
428 | | -* This guarantees that the currently running job can use a shared resource |
429 | | -* without another context accessing it. But, disabling interrupts, is a major |
430 | | -* undertaking. At best, the system will not be able to service interrupts for |
431 | | -* the time the current job is doing in its critical section, however, in QuarkTS++, |
432 | | -* these critical sections are handled as quickly as possible. |
433 | | -* |
434 | | -* Considering that the kernel is hardware-independent, the application writer |
435 | | -* should provide the necessary piece of code to enable and disable interrupts. |
436 | | -* |
437 | | -* For this, the qOS::critical::setInterruptsED() method should be used. In this way, |
438 | | -* communication between ISR and tasks using queued notifications or data queues |
439 | | -* is performed safely. |
440 | | -* |
441 | | -* In some systems, disabling the global IRQ flags is not enough, as they don't |
442 | | -* save/restore state of interrupt, so here, the @c uint32_t argument and |
443 | | -* return value in both functions (@c Disabler and @c Restorer) becomes relevant, |
444 | | -* because they can be used by the application writer to save and restore the |
445 | | -* current interrupt configuration. So, when a critical section is performed, |
446 | | -* the @c Disabler, in addition to disabling the interrupts, returns the current |
447 | | -* configuration to be retained by the kernel, later when the critical section |
448 | | -* finish, this retained value is passed to @c Restorer to bring back the saved |
449 | | -* configuration. |
| 421 | +* |
| 422 | +* Since the kernel is non-preemptive, the only critical sections that must be |
| 423 | +* handled are those involving shared resources accessed from ISR context. |
| 424 | +* The most straightforward way to achieve mutual exclusion is to temporarily |
| 425 | +* disable interrupts before entering a critical section and re-enable them |
| 426 | +* afterward. |
| 427 | +* |
| 428 | +* By disabling interrupts, the CPU cannot switch context, ensuring that the |
| 429 | +* currently running job accesses shared resources safely. However, this must |
| 430 | +* be done carefully and only for short periods. In QuarkTS++, critical |
| 431 | +* sections are minimized to keep interrupt latency as small as possible. |
| 432 | +* |
| 433 | +* Because the kernel is hardware-independent, the application developer must |
| 434 | +* provide the specific code for enabling and disabling interrupts. |
| 435 | +* |
| 436 | +* For this purpose, the qOS::critical::setInterruptsED() method should be |
| 437 | +* used. It allows the kernel to safely coordinate communication between ISRs |
| 438 | +* and tasks using queued notifications or data queues. |
| 439 | +* |
| 440 | +* Some MCUs require not only disabling global interrupt flags but also |
| 441 | +* saving and restoring the interrupt configuration. The @c uint32_t argument |
| 442 | +* and return values in the provided @c Disabler and @c Restorer functions are used |
| 443 | +* for this purpose. |
| 444 | +* |
| 445 | +* When a critical section is performed: |
| 446 | +* - The @c Disabler function disables interrupts and returns the previous |
| 447 | +* interrupt configuration. |
| 448 | +* - The kernel stores this configuration internally. |
| 449 | +* - After the critical section ends, the @c Restorer function restores |
| 450 | +* the saved configuration. |
| 451 | +* |
| 452 | +* |
| 453 | +* @subsection q_critical_examples Examples |
| 454 | +* |
| 455 | +* @subsubsection regintfcns Registering the interrupt control functions |
| 456 | +* |
| 457 | +* Before using any critical section, the application must register the |
| 458 | +* hardware-specific enable/disable routines: |
| 459 | +* |
| 460 | +* @code{.cpp} |
| 461 | +* using namespace qOS; |
| 462 | +* |
| 463 | +* static uint32_t disableInterrupts() { |
| 464 | +* uint32_t primask = __get_PRIMASK(); // Read current interrupt state |
| 465 | +* __disable_irq(); // Disable all interrupts |
| 466 | +* return primask; // Return the saved state |
| 467 | +* } |
| 468 | +* |
| 469 | +* static void restoreInterrupts(uint32_t primask) { |
| 470 | +* if (!primask) { |
| 471 | +* __enable_irq(); // Restore interrupt state |
| 472 | +* } |
| 473 | +* } |
| 474 | +* |
| 475 | +* void main( void ) { |
| 476 | +* critical::setInterruptsED(restoreInterrupts, disableInterrupts); |
| 477 | +* /* TODO : Setup OS and add tasks*/ |
| 478 | +* } |
| 479 | +* @endcode |
| 480 | +* |
| 481 | +* |
| 482 | +* @subsubsection usecritscope Using critical::scope for quick inline protection |
| 483 | +* |
| 484 | +* This construct provides minimal syntax overhead for protecting short |
| 485 | +* critical sections. The section is automatically exited when the scope ends. |
| 486 | +* |
| 487 | +* @code{.cpp} |
| 488 | +* void example() { |
| 489 | +* // Normal code (non-critical) |
| 490 | +* critical::scope { |
| 491 | +* // This block runs with interrupts disabled |
| 492 | +* sharedCounter++; |
| 493 | +* } |
| 494 | +* // Back to normal code (interrupts enabled) |
| 495 | +* } |
| 496 | +* @endcode |
| 497 | +* |
| 498 | +* |
| 499 | +* @subsubsection usecritlock Using critical::lock (RAII-style) |
| 500 | +* |
| 501 | +* The qOS::critical::lock class automatically manages entry and exit of a |
| 502 | +* critical section using RAII semantics. When the object is created, interrupts |
| 503 | +* are disabled; when it goes out of scope, interrupts are restored. |
| 504 | +* |
| 505 | +* @code{.cpp} |
| 506 | +* void example() { |
| 507 | +* critical::lock lockGuard; // interrupts disabled here |
| 508 | +* |
| 509 | +* sharedBuffer.push(value); // safe shared access |
| 510 | +* |
| 511 | +* } // lockGuard destroyed → interrupts restored |
| 512 | +* @endcode |
450 | 513 | * |
451 | 514 | * @section q_configmacros Configuration macros |
452 | 515 | * Some OS features can be customized using a set of macros located in the header |
|
0 commit comments