Subversion Repositories HelenOS-doc

Rev

Rev 73 | Rev 82 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 73 Rev 81
Line 464... Line 464...
464
        <primary>synchronization</primary>
464
        <primary>synchronization</primary>
465
 
465
 
466
        <secondary>- futex</secondary>
466
        <secondary>- futex</secondary>
467
      </indexterm>
467
      </indexterm>
468
 
468
 
-
 
469
      <para>In a multithreaded environment, userspace threads need an
-
 
470
      efficient way to synchronize. HelenOS borrows an idea from Linux<xref
-
 
471
      linkend="futex" /> to implement lightweight userspace synchronization
-
 
472
      and mutual exclusion primitive called futex. The key idea behind futexes
-
 
473
      is that non-contended synchronization is very fast and takes place only
-
 
474
      in userspace without kernel's intervention. When more threads contend
-
 
475
      for a futex, only one of them wins; other threads go to sleep via a
-
 
476
      dedicated syscall.</para>
-
 
477
 
-
 
478
      <para>The userspace part of the futex is a mere integer variable, a
-
 
479
      counter, that can be atomically incremented or decremented. The kernel
-
 
480
      part is rather more complicated. For each userspace futex counter, there
-
 
481
      is a kernel structure describing the futex. This structure
-
 
482
      contains:</para>
-
 
483
 
-
 
484
      <itemizedlist>
-
 
485
        <listitem>
-
 
486
          <para>number of references,</para>
-
 
487
        </listitem>
-
 
488
 
-
 
489
        <listitem>
-
 
490
          <para>physical address of the userspace futex counter,</para>
-
 
491
        </listitem>
-
 
492
 
-
 
493
        <listitem>
-
 
494
          <para>hash table link and</para>
-
 
495
        </listitem>
-
 
496
 
-
 
497
        <listitem>
-
 
498
          <para>a wait queue.</para>
-
 
499
        </listitem>
-
 
500
      </itemizedlist>
-
 
501
 
-
 
502
      <para>The reference count helps to find out when the futex is no longer
-
 
503
      needed and can be deallocated. The physical address is used as a key for
-
 
504
      the global futex hash table. Note that the kernel has to use physical
-
 
505
      address to identify the futex beacause one futex can be used for
-
 
506
      synchronization among different address spaces and can have different
-
 
507
      virtual addresses in each of them. Finally, the kernel futex structure
-
 
508
      includes a wait queue. The wait queue is used to put threads that didn't
-
 
509
      win the futex to sleep until the winner wakes one of them up.</para>
-
 
510
 
-
 
511
      <para>A futex should be initialized by setting its userspace counter to
-
 
512
      one before it is used. When locking the futex via userspace library
-
 
513
      function <code>futex_down_timeout</code>, the library code atomically
-
 
514
      decrements the futex counter and tests if it droped below zero. If it
-
 
515
      did, then the futex is locked by another thread and the library uses the
-
 
516
      <constant>SYS_FUTEX_SLEEP</constant> syscall to put the thread asleep.
-
 
517
      If the counter decreased to 0, then there was no contention and the
-
 
518
      thread can enter the critical section protected by the futex. When the
-
 
519
      thread later leaves that critical section, it, using library function
-
 
520
      <code>futex_up</code>, atomically increments the counter. If the counter
-
 
521
      value increased to one, then there again was no contention and no action
-
 
522
      needs to be done. However, if it increased to zero or even a smaller
-
 
523
      number, then there are sleeping threads waiting for the futex to become
-
 
524
      available. In that case, the library has to use the
-
 
525
      <constant>SYS_FUTEX_WAKEUP</constant> syscall to wake one sleeping
469
      <para></para>
526
      thread.</para>
-
 
527
 
-
 
528
      <para>So far, futexes are very elegant in that they don't interfere with
-
 
529
      the kernel when there is no contention for them. Another nice aspect of
-
 
530
      futexes is that they don't need to be registered anywhere prior to the
-
 
531
      first kernel intervention.</para>
-
 
532
 
-
 
533
      <para>Both futex related syscalls, <constant>SYS_FUTEX_SLEEP</constant>
-
 
534
      and <constant>SYS_FUTEX_WAKEUP</constant>, respectivelly, are mere
-
 
535
      wrappers for <code>waitq_sleep_timeout</code> and
-
 
536
      <code>waitq_sleep_wakeup</code>, respectively, with some housekeeping
-
 
537
      functionality added. Both syscalls need to translate the userspace
-
 
538
      virtual address of the futex counter to physical address in order to
-
 
539
      support synchronization accross shared memory. Once the physical address
-
 
540
      is known, the kernel checks whether the futexes are already known to it
-
 
541
      by searching the global futex hash table for an item with the physical
-
 
542
      address of the futex counter as a key. When the search is successful, it
-
 
543
      returns an address of the kernel futex structure associated with the
-
 
544
      counter. If the hash table does not contain the key, the kernel creates
-
 
545
      it and inserts it into the hash table. At the same time, the the current
-
 
546
      task's B+tree of known futexes is searched in order to find out if the
-
 
547
      task already uses the futex. If it does, no action is taken. Otherwise
-
 
548
      the reference count of the futex is incremented, provided that the futex
-
 
549
      already existed.</para>
470
    </section>
550
    </section>
471
  </section>
551
  </section>
472
</chapter>
552
</chapter>
473
553