<!--
     The FreeBSD Russian Documentation Project

     The FreeBSD SMP Next Generation Project

     $FreeBSD$
     $FreeBSDru: frdp/doc/ru_RU.KOI8-R/books/developers-handbook/locking/chapter.sgml,v 1.1 2001/02/19 06:44:22 andy Exp $

     Original revision: 1.2
-->

<chapter id="locking">
  <title>Замечания по блокировке</title>

  <para><emphasis>Эта глава поддерживается проектом FreeBSD SMP Next
    Generation Project
    <email>freebsd-smp@FreeBSD.org</email>.</emphasis></para>

  <para>Этот документ описывает механизм блокировки, используемый в ядре
    FreeBSD для обеспечения эффективной поддержки нескольких процессоров в
    ядре.  Блокировку можно рассматривать с нескольких точек зрения.
    Структуры данных могут быть защищены с помощью блокировок mutex или
    &man.lockmgr.9;.  Несколько переменных защищены просто в силу атомарности
    используемых для доступа к ним операций.</para>

  <sect1>
    <title>Мьютексы</title>

    <para>Мьютекс (mutex) - это просто блокировка, используемая для
      реализации гарантированной исключительности.  В частности, в каждый
      момент времени мьютексом может владеть только один объект.  Если
      какой-то объект хочет получить мьютекс, который уже кто-то занял, он
      должен дождаться момента его освобождения.  В ядре FreeBSD владельцами
      мьютексов являются процессы.</para>

    <para>Мьютексы могут быть затребованы рекурсивно, но предполагается, что
      они занимаются на короткое время.  В частности, владельцу мьютекса
      нельзя выдерживать паузу.  Если вам нужно выполнить блокировку на время
      паузы, используйте блокировку через &man.lockmgr.9;.</para>

    <para>Каждый мьютекс имеет несколько представляющих интерес
      характеристик:</para>

    <variablelist>
      <varlistentry>
        <term>Имя переменной</term>
        <listitem>
          <para>Имя переменной <type>struct mtx</type> в исходных текстах
            ядра.</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>Логическое имя</term>
        <listitem>
          <para>Имя мьютекса, назначенное ему через
            <function>mtx_init</function>.  Это имя выводится в сообщениях
            трассировки KTR и диагностических предупреждающих и ошибочных
            сообщениях и используется для идентификации мьютексов в
            отладочном коде.</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>Тип</term>
        <listitem>
          <para>Тип мьютекса в терминах флагов <constant>MTX_*</constant>.
            Значение каждого флага связано с его смыслом так, как это описано
            в &man.mutex.9;.</para>

          <variablelist>
            <varlistentry>
              <term><constant>MTX_DEF</constant></term>
              <listitem>
                <para>Sleep-мьютекс</para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><constant>MTX_SPIN</constant></term>
              <listitem>
                <para>Spin-мьютекс</para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><constant>MTX_COLD</constant></term>
              <listitem>
                <para>Этот мьютекс инициализируется очень рано.  Поэтому он
                  должен быть объявлен через функции
                  <function>MUTEX_DECLARE</function>, а флаг
                  <constant>MTX_COLD</constant> должен быть передан в функцию
                  <function>mtx_init</function>.</para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><constant>MTX_TOPHALF</constant></term>
              <listitem>
                <para>Этот spin-мьютекс не запрещает прерывания.</para>
              </listitem>
            </varlistentry>

            <varlistentry>
              <term><constant>MTX_NORECURSE</constant></term>
              <listitem>
                <para>Этот мьютекс не разрешается блокировать
                  рекурсивно.</para>
              </listitem>
            </varlistentry>
          </variablelist>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>Защиты</term>
        <listitem>
          <para>Список структур данных или членов структур данных, которые
            защищает этот мьютекс.  Для членов структур данных иям будет в
            форме
            <structname/имя структуры/.<structfield/имя члена
            структуры/.</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>Зависимые функции</term>
        <listitem>
          <para>Функции, которые можно вызвать, если этот мьютекс
            занят.</para>
        </listitem>
      </varlistentry>
    </variablelist>

    <table frame="all" colsep="1" rowsep="1" pgwide="1">
      <title>Список мьютексов</title>

      <tgroup cols="5">
        <thead>
          <row>
            <entry>Имя переменной</entry>
            <entry>Логическое имя</entry>
            <entry>Тип</entry>
            <entry>Защиты</entry>
            <entry>Зависимые функции</entry>
          </row>
        </thead>

        <!-- Блокировка планировщика задач -->
        <tbody>
          <row>
            <entry>sched_lock</entry>
            <entry><quote>sched lock</quote></entry>
            <entry>
              <constant>MTX_SPIN</constant> |
              <constant>MTX_COLD</constant>
            </entry>
            <entry>
              <varname>_gmonparam</varname>,
              <varname>cnt.v_swtch</varname>,
              <varname>cp_time</varname>,
              <varname>curpriority</varname>,
              <structname/mtx/.<structfield/mtx_blocked/,
              <structname/mtx/.<structfield/mtx_contested/,
              <structname/proc/.<structfield/p_contested/,
              <structname/proc/.<structfield/p_blocked/,
              <structname/proc/.<structfield/p_flag/
                (<constant>P_PROFIL</constant> XXX,
                 <constant>P_INMEM</constant>,
                 <constant>P_SINTR</constant>,
                 <constant>P_TIMEOUT</constant>,
                 <constant>P_SWAPINREQ</constant> XXX,
                 <constant>P_INMEN</constant> XXX),
              <structname/proc/.<structfield/p_nice/,
              <structname/proc/.<structfield/p_procq/,
              <structname/proc/.<structfield/p_blocked/,
              <structname/proc/.<structfield/p_estcpu/,
              <structname/proc/.<structfield/p_nativepri/,
              <structname/proc/.<structfield/p_priority/,
              <structname/proc/.<structfield/p_usrpri/,
              <structname/proc/.<structfield/p_rtprio/,
              <structname/proc/.<structfield/p_rqindex/,
              <structname/proc/.<structfield/p_stats->p_prof/,
              <structname/proc/.<structfield/p_stats->p_ru/,
              <structname/proc/.<structfield/p_stat/,
              <structname/proc/.<structfield/p_cpticks/
              <structname/proc/.<structfield/p_iticks/,
              <structname/proc/.<structfield/p_uticks/,
              <structname/proc/.<structfield/p_sticks/,
              <structname/proc/.<structfield/p_swtime/,
              <structname/proc/.<structfield/p_slptime/,
              <structname/proc/.<structfield/p_runtime/,
              <structname/proc/.<structfield/p_pctcpu/,
              <structname/proc/.<structfield/p_oncpu/,
              <structname/proc/.<structfield/p_asleep/,
              <structname/proc/.<structfield/p_wchan/,
              <structname/proc/.<structfield/p_wmesg/,
              <structname/proc/.<structfield/p_slpq/,
              <structname/proc/.<structfield/p_vmspace/
                (XXX - в <function>statclock</function>),
              <varname>pscnt</varname>,
              <varname>slpque</varname>,
              <varname>itqueuebits</varname>,
              <varname>itqueues</varname>,
              <varname>rtqueuebits</varname>,
              <varname>rtqueues</varname>,
              <varname>queuebits</varname>,
              <varname>queues</varname>,
              <varname>idqueuebits</varname>,
              <varname>idqueues</varname>,
              <varname>switchtime</varname>,
            </entry>
            <entry>
              <function>setrunqueue</function>,
              <function>remrunqueue</function>,
              <function>mi_switch</function>,
              <function>chooseproc</function>,
              <function>schedclock</function>,
              <function>resetpriority</function>,
              <function>updatepri</function>,
              <function>maybe_resched</function>,
              <function>cpu_switch</function>,
              <function>cpu_throw</function>
            </entry>
          </row>

          <!-- The vm86 pcb lock -->
          <row>
            <entry>vm86pcb_lock</entry>
            <entry><quote>vm86pcb lock</quote></entry>
            <entry>
              <constant>MTX_DEF</constant> |
              <constant>MTX_COLD</constant>
            </entry>
            <entry>
              <varname>vm86pcb</varname>
            </entry>
            <entry>
              <function>vm86_bioscall</function>
            </entry>
          </row>

          <!-- Giant -->
          <row>
            <entry>Giant</entry>
            <entry><quote>Giant</quote></entry>
            <entry>
              <constant>MTX_DEF</constant> |
              <constant>MTX_COLD</constant>
            </entry>
            <entry>nearly everything</entry>
            <entry>lots</entry>
          </row>

          <!-- The callout lock -->
          <row>
            <entry>callout_lock</entry>
            <entry><quote>callout lock</quote></entry>
            <entry>
              <constant>MTX_SPIN</constant>
            </entry>
            <entry>
              <varname>callfree</varname>,
              <varname>callwheel</varname>,
              <varname>nextsoftcheck</varname>,
              <structname/proc/.<structfield/p_itcallout/,
              <structname/proc/.<structfield/p_slpcallout/,
              <varname>softticks</varname>,
              <varname>ticks</varname>
            </entry>
            <entry>
            </entry>
          </row>
        </tbody>
      </tgroup>
    </table>
  </sect1>

  <sect1>
    <title>Блокировки менеджера блокировок</title>

    <para>Блокировки, которые даются через интерфейс &man.lockmgr.9;,
      являются блокировками менеджера блокировок.  Эти блокировки являются
      блокировками на чтение/запись и ими могут владеть процессы в состоянии
      ожидания.</para>

    <table>
      <title>Список блокировок &man.lockmgr.9;</title>

      <tgroup cols="2">
        <thead>
          <row>
            <entry>Имя переменной</entry>
            <entry>Защиты</entry>
          </row>
        </thead>
        <tbody>
          <row>
            <entry><varname>allproc_lock</varname></entry>
            <entry>
              <varname>allproc</varname>
              <varname>zombproc</varname>
              <varname>pidhashtbl</varname>
              <structname/proc/.<structfield/p_list/
              <structname/proc/.<structfield/p_hash/
              <varname>nextpid</varname>
            </entry>
            <entry><varname>proctree_lock</varname></entry>
            <entry>
              <structname/proc/.<structfield/p_children/
              <structname/proc/.<structfield/p_sibling/
            </entry>
          </row>
        </tbody>
      </tgroup>
    </table>
  </sect1>

  <sect1>
    <title>Атомарно защищенные переменные</title>

    <para>Переменной, защищенной атомарно, является особая переменная,
      которая не защищается явной блокировкой.  Вместо этого для доступа к
      данным переменных используются специальные атомарные операции, как
      описано в &man.atomic.9;.  Лишь несколько переменных используются таким
      образом, хотя другие примитивы синхронизации, такие как мьютексы,
      реализованы с атомарно защищенными переменными.</para>

    <itemizedlist>
      <listitem>
        <para><varname>astpending</varname></para>
      </listitem>

      <listitem>
        <para><structname/mtx/.<structfield/mtx_lock/</para>
      </listitem>
    </itemizedlist>
  </sect1>
</chapter>
