Rev 55 | Rev 58 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 55 | Rev 56 | ||
---|---|---|---|
Line 86... | Line 86... | ||
86 | structure called <classname>timeout</classname>. Timeouts are registered |
86 | structure called <classname>timeout</classname>. Timeouts are registered |
87 | via <code>timeout_register</code> function. This function takes a pointer |
87 | via <code>timeout_register</code> function. This function takes a pointer |
88 | to a timeout structure, a callback function, a parameter of the callback |
88 | to a timeout structure, a callback function, a parameter of the callback |
89 | function and a delay in microseconds as parameters. After the structure is |
89 | function and a delay in microseconds as parameters. After the structure is |
90 | initialized with all these values, it is sorted into the processor's list |
90 | initialized with all these values, it is sorted into the processor's list |
91 | of active timeouts.Timeouts are sorted in this list according to the |
91 | of active timeouts, according to the number of clock interrupts remaining |
92 | number of clock interrupts remaining to their expiration and relative to |
92 | to their expiration and relatively to already listed timeouts.</para> |
93 | each other. </para> |
- | |
94 | 93 | ||
95 | <para>Timeouts can be unregistered via <code>timeout_unregister</code>. |
94 | <para>Timeouts can be unregistered via <code>timeout_unregister</code>. |
96 | This function can, as opposed to <code>timeout_register</code>, fail when |
95 | This function can, as opposed to <code>timeout_register</code>, fail when |
97 | it is too late to remove the timeout from the list of active |
96 | it is too late to remove the timeout from the list of active |
98 | timeouts.</para> |
97 | timeouts.</para> |
Line 127... | Line 126... | ||
127 | <listitem> |
126 | <listitem> |
128 | <para>preemption of threads.</para> |
127 | <para>preemption of threads.</para> |
129 | </listitem> |
128 | </listitem> |
130 | </itemizedlist> |
129 | </itemizedlist> |
131 | 130 | ||
132 | <para>The first two goals are performed exactly one more times than is the |
131 | <para>The <code>clock</code> function checks for expired timeouts and |
- | 132 | decrements unexpired timeout expiration counters exactly one more times |
|
133 | number of missed clock signals (i.e. at least once and possibly more |
133 | than is the number of missed clock signals (i.e. at least once and |
134 | times, depending on the missed clock signals counter). The remaining |
134 | possibly more times, depending on the missed clock signals counter). The |
- | 135 | time of the day counters are also updated one more times than is the |
|
- | 136 | number of missed clock signals. And finally, the remaining timeslice of |
|
135 | timeslice of the running thread is decremented also with respect to this |
137 | the running thread is decremented with respect to this counter as well. By |
136 | counter. By considering its value, the kernel performs actions that would |
138 | considering its value, the kernel performs actions that would otherwise be |
137 | otherwise be lost due to an occasional excessive time drift described in |
139 | lost due to an occasional excessive time drift described in previous |
138 | previous paragraphs.</para> |
140 | paragraphs.</para> |
- | 141 | </section> |
|
- | 142 | ||
- | 143 | <section> |
|
- | 144 | <title>Time source for userspace</title> |
|
- | 145 | ||
- | 146 | <para>In HelenOS, userspace tasks don't communicate with the kernel in |
|
- | 147 | order to read system time. Instead, a mechanism that shares kernel time of |
|
- | 148 | the day counters with userspace address spaces is deployed. On the kernel |
|
- | 149 | side, during system initialization, HelenOS allocates a frame of physical |
|
- | 150 | memory and stores the time of the day counters there. The counters have |
|
- | 151 | the following structure:</para> |
|
- | 152 | ||
- | 153 | <itemizedlist> |
|
- | 154 | <listitem> |
|
- | 155 | <para>first 32-bit counter for seconds,</para> |
|
- | 156 | </listitem> |
|
- | 157 | ||
- | 158 | <listitem> |
|
- | 159 | <para>32-bit counter for microseconds and</para> |
|
- | 160 | </listitem> |
|
- | 161 | ||
- | 162 | <listitem> |
|
- | 163 | <para>second 32-bit counter for seconds.</para> |
|
- | 164 | </listitem> |
|
- | 165 | </itemizedlist> |
|
- | 166 | ||
- | 167 | <para>One of the userspace tasks with capabilities of memory manager (e.g. |
|
- | 168 | ns) asks the kernel to map this frame into its address space. Other, |
|
- | 169 | non-privileged, tasks then use IPC to communicate read-only sharing of |
|
- | 170 | this memory. Reading time in a userspace task is therefore just a matter |
|
- | 171 | of reading memory.</para> |
|
- | 172 | ||
- | 173 | <para>There are two interesting points about this. First, the counters are |
|
- | 174 | 32-bit even on 64-bit machines. The goal is to provide subsecond precision |
|
- | 175 | with the possibility to span roughly 136 years. Note that a single 64-bit |
|
- | 176 | microsecond counter could not be usually read atomically on 32-bit |
|
- | 177 | platforms. Now the second point is that 32-bit platforms cannot atomically |
|
- | 178 | read two 32-bit counters either. However, a generic protocol is used to |
|
- | 179 | guarantee that sequentially read times will create a non-decreasing |
|
- | 180 | sequence.</para> |
|
- | 181 | ||
- | 182 | <para>The problematic part is updating both seconds and microseconds once |
|
- | 183 | in a second. Seconds must be incremented and microseconds must be reset. |
|
- | 184 | However, without any synchronization, the two kernel stores and the two |
|
- | 185 | userspace reads can arbitrarily interleave. Furthemore, the reader has no |
|
- | 186 | chance to detect that the counters were updated only from half. Therefore |
|
- | 187 | three counters are used in HelenOS.</para> |
|
- | 188 | ||
- | 189 | <para>If seconds need to be updated, the kernel increments the first |
|
- | 190 | second counter, issues a write memory barrier operation, updates the |
|
- | 191 | microsecond counter, issues another write memory barrier operation and |
|
- | 192 | increments the second second counter. When only microseconds need to be |
|
- | 193 | updated, no special action is taken by the kernel. On the other hand, the |
|
- | 194 | userspace task must always read all three counters and in reversed order. |
|
- | 195 | A read memory barrier operation must be issued between each two reads. A |
|
- | 196 | non-atomic read is detected when the two second counters differ. The |
|
- | 197 | userspace library solves this situation by returning zero instead of the |
|
- | 198 | value read from the microsecond counter.</para> |
|
139 | </section> |
199 | </section> |
140 | </chapter> |
200 | </chapter> |
141 | 201 |