// vi:ft=c
/**

\page l4re_pthreads Pthread Support

L4Re supports the standard pthread library functionality. Therefore L4Re
itself does not contain any documentation for pthreads itself. Please refer
to the standard pthread documentation instead.

The L4Re specific parts will be described herein.

<ul>
  <li>
    Include pthread-l4.h header file:
  \code
   #include <pthread-l4.h>
  \endcode

  </li>
  <li>Return the local thread capability of a pthread thread:

  Use \c pthread_l4_cap(pthread_t t) to get the capability index of
  the pthread t.

  For example:
  \code
  pthread_l4_cap(pthread_self());
  \endcode
  </li>

  <li> Setting the L4 priority of an L4 thread works with a special
       scheduling policy (other policies do not affect the L4 thread
       priority):

  \code
  pthread_t t;
  pthread_attr_t a;
  struct sched_param sp;

  pthread_attr_init(&a);
  sp.sched_priority = l4_priority;
  pthread_attr_setschedpolicy(&a, SCHED_L4);
  pthread_attr_setschedparam(&a, &sp);
  pthread_attr_setinheritsched(&a, PTHREAD_EXPLICIT_SCHED);

  if (pthread_create(&t, &a, pthread_func, NULL))
    // failure...

  pthread_attr_destroy(&a);
  \endcode

  </li>

  <li> You can prevent your pthread from running immediately after the call to
       \c pthread_create(..) by adding \c PTHREAD_L4_ATTR_NO_START to the
       \c create_flags of the pthread attributes. To finally start the thread
       you need to call \c scheduler()->run_thread() passing the capability
       of the pthread and scheduling parameters.

    \code
      pthread_t t;
      pthread_attr_t attr;

      pthread_attr_init(&attr);
      attr.create_flags |= PTHREAD_L4_ATTR_NO_START;

      if (pthread_create(&t, &attr, pthread_func, nullptr))
        // failure...

      pthread_attr_destroy(&attr);

      // do stuff

      auto ret = L4Re::Env::env()->scheduler()->run_thread(pthread_l4_cap(t),
                                                           l4_sched_param(2));
      if (l4_error(ret))
        // failure...
    \endcode

  </li>
</ul>


<h4>
  Constraints on pthread_t, user-land capability slot, and kernel thread-object
</h4>

<ul>
  <li>
    `pthread_l4_cap()` is guaranteed to return the valid capability slot
    of the pthread (A) until `pthread_join()` or `pthread_detach()` is invoked
    on (A)'s `pthread_t`.
  </li>

  <li>
    `pthread_l4_cap()` exposes internal state of the pthread management, take
    the necessary precautions as you would for any shared data in concurrent
    environments.
    If you use `pthread_l4_cap()` guarding against concurrency issues is your
    duty.
  </li>

  <li>
    There is no guarantee that a valid capability slot points to a
    present capability.
  </li>

  <li>
    <b>Example</b>

    It is possible to obtain a valid thread capability slot and for
    `l4_task_cap_valid()` to return the capability as not present.
    The following example showcases a possible sequence of events.
  \code
    // Assume: void some_func(void *)
    pthread_t pthread = nullptr;
    pthread_create(&pthread, nullptr, some_func, nullptr);

    // pthread running some_func()
    l4_cap_idx_t cap_idx = pthread_l4_cap(pthread);
    l4_is_valid_cap(cap_idx); // ---> true

    long valid = l4_task_cap_valid(L4RE_THIS_TASK_CAP, cap_idx).label());
    // valid == 1 --> capability object is present (refers to a kernel object).


    // some_func() exits

    cap_idx = pthread_l4_cap(pthread);
    l4_is_valid_cap(cap_idx); // ---> true

    valid = l4_task_cap_valid(L4RE_THIS_TASK_CAP, cap_idx).label());
    // valid == 0 --> capability object is not present (refers to no kernel object).


    pthread_join(pthread, nullptr); // invalidates the cap slot and frees
                                    // the pthread's data structures

    // using cap_idx here is undefined behavior.

  \endcode
  </li>
</ul>


*/
