| Both sides previous revision Previous revision Next revision | Previous revision |
| andriygapon:avgsyscons [2011/12/17 20:40] – wip AndriyGapon | andriygapon:avgsyscons [2016/07/21 11:02] (current) – Move user articles under user heirarchy KubilayKocak |
|---|
| ===== Special contexts and locking ===== | ===== Special contexts and locking ===== |
| |
| ==== Pause after each line mode ==== | ==== 1. Pause after each line mode ==== |
| This is an early boot context. This mode is not supported by all the keyboard drivers. Only drivers that support early initialization (before usual discovery of system resources) can support this mode. As such, the ''%%ukbd%%'' driver doesn't support this mode. In this mode interrupts are not enabled yet, there is only a single ''%%thread0%%'' running and so the polling works naturally without any complications. | This is an early boot context. This mode is not supported by all the keyboard drivers. Only drivers that support early initialization (before usual discovery of system resources) can support this mode. As such, the ''%%ukbd%%'' driver doesn't support this mode. In this mode interrupts are not enabled yet, there is only a single ''%%thread0%%'' running and so the polling works naturally without any complications. |
| It seems that at present the ''%%atkbd%%'' driver doesn't properly handle its own "non-early" initialization if this mode is active. | It seems that at present the ''%%atkbd%%'' driver doesn't properly handle its own "non-early" initialization if this mode is active. |
| |
| ==== mountroot prompt ==== | ==== 2. mountroot prompt ==== |
| At this stage the interrupts are already enabled and there are multiple threads of execution. There are still no userland processes. This is the most complex context from the point of view of locking. The keyboard driver's interrupt handler may get invoked but it must not interfere with kernel polling. | At this stage the interrupts are already enabled and there are multiple threads of execution. There are still no userland processes. This is the most complex context from the point of view of locking. The keyboard driver's interrupt handler may get invoked but it must not interfere with kernel polling. |
| So, in this context in particular, the keyboard drivers must ensure that either their interrupt handler do not fire or that they do not modify parts of the internal state that can be concurrently accessed by the polling code path. | So, in this context in particular, the keyboard drivers must ensure that either their interrupt handler do not fire or that they do not modify parts of the internal state that can be concurrently accessed by the polling code path. |
| | Giant is already held in this context - it is acquired in ''%%start_init%%'' before the ''%%vfs_mountroot%%'' call. |
| |
| ==== KDB/DDB context ==== | ==== 3. KDB/DDB context ==== |
| In this context the kernel is essentially single-threaded. All but one CPUs are paused and only one thread is executing. In this case there is no need for protection from concurrent access. Additionally the only executing thread must not get blocked on any locks, so it explicitly should bypass any normal locking. Polling should work out naturally in this case. | In this context the kernel is essentially single-threaded. All but one CPUs are paused and only one thread is executing. In this case there is no need for protection from concurrent access. Additionally the only executing thread must not get blocked on any locks, so it explicitly should bypass any normal locking. Polling should work out naturally in this case. |
| |
| ==== Panic context with SCHEDULER_STOPPED ==== | ==== 4. Panic context with SCHEDULER_STOPPED ==== |
| This context is very similar to the above context by its properties. The difference is all the locks are automatically bypassed, so there is no need for explicit checks. | This context is very similar to the above context by its properties. The difference is all the locks are automatically bypassed, so there is no need for explicit checks. |
| |
| ==== Late shutdown context ==== | ==== 5. Late shutdown context ==== |
| This is a context where the kernel may ask to press a key for some action. E.g. after ''%%shutdown -h%%'' the kernel asks "to press any key to reboot". This case is rather similar to the first case. | This is a context where the kernel may ask to press a key for some action. E.g. after ''%%shutdown -h%%'' the kernel asks "to press any key to reboot". At this stage the interrupts and the scheduler should still be functional. The ''%%Giant%%'' is held by the shutdown thread - it's taken in ''%%sys_reboot%%''. |
| | |
| | ==== Summary ==== |
| | It's important to note that the normal locking is usable in all of the above contexts except the number 3. In the contexts 1, 2 and 5 it simply just works, in the context 4 the locking is auto-magically skipped. So any explicit locking in the code that can be executed in the context 3 must have an explicit check for ''%%kdb_active%%''. |
| | |
| | Another important note is that there are three ways to call into the ''%%syscons%%'' code and into the keyboard drivers code: |
| | * from the tty layer |
| | * from interrupt handlers and callouts |
| | * from the kernel in polling mode |
| | The first two are already protected by the proper ''%%Giant%%'' locking, so there is no need for additional locking in these code paths. On the other hand the entry points for the third path must be explicitly protected. That protection must obey the previous rule about ''%%kdb_active%%''. |
| | |
| | Additional observation is that the kernel never really competes with the userland for access to the keyboard(s). The kernel polls the console for input either when there is no userland yet or there is no userland already or either ''%%panic%%'' or ''%%kdb%%'' are entered and the userland is "suspended". |
| | Also, it can be seen that at present there is no concurrent access to the console input from the kernel side too. So the code doesn't expect this and is not equipped to properly handle such a situation yet. |
| | |
| | One more thing to note is that at present the kernel always accesses the console input in a well-defined locking locking context. Either it is a "single-threaded"/"lock-less" context of the ''%%panic%%''/''%%kdb%%'' or a rather clean context of a specific system boot or shutdown stage. |
| | |
| | ===== Interaction between the input and output paths ===== |
| | |
| | The current code has one non-trivial interaction between the output path and input path. ''%%syscons%%'' tries to provide the following behavior: if a Scroll Lock mode is active and kernel prints something to a console, the the Scroll Lock must be deactivated and correspondingly a Scroll Lock LED on a keyboard must be turned off. As mentioned above, the kernel may produce output from arbitrary contexts, but turning off the LED requires calling into the keyboard drivers which require specific locking and currently use the ''%%Giant%%''. So a direct call may result in a LOR and potentially a deadlock (provided that all the locking requirements are properly satisfied). One way to work around this problem is to execute the action asynchronously via a ''%%taskqueue%%''. |
| | |
| | ===== ukbd ===== |
| | |
| | The problem with ''%%ukbd%%'' is that it has to interact with rather complex hardware compared to AT compatible keyboard controller, besides also unlike the AT keyboard controller the USB controller can be shared with rather non-trivial peripherals and their drivers. By necessity the underlying USB subsystem must use multiple threads in most of the contexts. Thus the ''%%ukbd%%'' driver must honor concurrency and locking strategies of the USB subsystem when the USB threads are active. |
| | |
| | Summary. Context 1 is not applicable to the ''%%ukbd%%''. In contexts 3 and 4 the USB threads do not run, so the ''%%ukbd%%'' doesn't have to acquire any locks (in fact in context 3 it must not acquire any locks) and also it must directly go all the way to hardware via direct calls. In context 2 the ''%%ukbd%%'' must acquire the necessary locks, the ''%%Giant%%'' currently, if it is called via routines related to polling. It's important to note that in this context the ''%%ukbd%%'' driver works in interrupt driven mode internally. The USB threads are running and they perform the actual interaction with the hardware. So the ''%%ukbd%%'' must not access the hardware directly. Also, if it has to sleep/wait for the USB threads, then it should release the ''%%Giant%%'' while doing so, so that the USB threads can interact with the ''%%ukbd%%'' under ''%%Giant%%'' protection. ukbd is detached before context 5 is entered, so it is useless there and that context is irrelevant to ukbd. |
| | |
| | Routines for non-polling access should already be called with the proper locks, that fact can be asserted in the code. |
| |