Museum

Home

Lab Overview

Retrotechnology Articles

⇒ Online Manual

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

system_clock(3K)

event_flags(3K)



event_counters(3K)                SDK R4.11               event_counters(3K)


NAME
       event_counters: lm_add_to_ec_value, lm_advance_ec, lm_await_events,
       lm_convert_clock_value_to_ec_value,
       lm_convert_ec_value_to_clock_value, lm_get_next_ec_value,
       lm_has_event_occurred, lm_increment_ec_value, lm_initialize_ec,
       lm_initialize_sequencer, lm_read_ec, lm_ticket_sequencer,
       lm_are_ec_values_equal - handle event counters

SYNOPSIS
       #include "/usr/src/uts/aviion/ii/i_lm.h"


       void                  lm_add_to_ec_value                 (
       lm_ec_value_ptr_type         ec_value_ptr,          READ_WRITE
       uint32_type                  addend                 READ_ONLY
                                                                )

       void                  lm_advance_ec                      (
       lm_eventcounter_name         ec_name,               READ_WRITE
                                                                )

       boolean_type          lm_are_ec_values_equal             (
       lm_ec_value_type             value1,                READ_ONLY
       lm_ec_value_type             value2                 READ_ONLY
                                                                )

       void                  lm_await_events                    (
       lm_event_type                caller_event_list[],   READ_ONLY
       int32_type                   caller_list_size,      READ_ONLY
       int32_ptr_type               list_index_ptr         WRITE_ONLY
                                                                )

       lm_ec_value_type      lm_convert_clock_value_to_ec_value (
       misc_clock_value_ptr_type    clock_value_ptr        READ_ONLY
                                                                )

       void                  lm_convert_ec_value_to_clock_value (
       lm_ec_value_type             ec_value,              READ_ONLY
       misc_clock_value_ptr_type    clock_value_ptr        WRITE_ONLY
                                                                )

       lm_ec_value_type      lm_get_next_ec_value               (
       lm_ec_ptr_type               ec_name                READ_ONLY
                                                                )

       boolean_type          lm_has_event_occurred              (
       lm_event_ptr_type            event_ptr              READ_ONLY
                                                                )

       void                  lm_increment_ec_value              (
       lm_ec_value_ptr_type         ec_value_ptr           READ_WRITE
                                                                )

       void                  lm_initialize_ec                   (
       lm_ec_ptr_type               ec_name                READ_ONLY
                                                                )

       void                  lm_initialize_sequencer            (
       lm_ec_ptr_type               seq_name               READ_ONLY
                                                                )

       lm_ec_value_type      lm_read_ec                         (
       lm_ec_ptr_type               ec_name                READ_ONLY
                                                                )

       void                  lm_ticket_sequencer                (
       lm_ec_ptr_type                seq_name,             READ_ONLY
       lm_ec_value_ptr_type          seq_value_ptr         WRITE_ONLY
                                                                )

   where:
       addend          The value to be added to the event-counter value.
       clock_value_ptr A pointer to a clock value or to the location where
                       the clock value is to be written.
       ec_name         A pointer to the event counter to be advanced,
                       initialized, or read.
       ec_value_ptr    A pointer to an event-counter value or to the
                       location where the event-counter value (or the event-
                       counter value plus one) is to be written.
       event_list      An array of events for which the LWP (Light-Weight
                       Process, or thread) will await.
       event_ptr       A pointer to the subject event.
       list_index_ptr  A pointer to the array index (zero based) of an event
                       that is satisfied when the call returns.
       list_size       The number of elements in event_list.
       seq_name        A pointer to the sequencer to be initialized or
                       ticketed.
       seq_value_ptr   A pointer to the location in which the new value of
                       the sequencer is to be written.
       value1_ptr      A pointer to an event-counter value.
       value2_ptr      A pointer to an event-counter value.

DESCRIPTION
       The following routines are described in this man page:
       f4lm_add_to_ec_value               Add amount to event counter value
       lm_advance_ec                      Add one to an event counter and
                                          awaken waiting LWPs.
       lm_await_events                    Perform await operation on one or
                                          more events
       lm_convert_clock_value_to_ec_value Convert a clock value into an
                                          event-counter value
       lm_convert_ec_value_to_clock_value Convert an event-counter value
                                          into a clock value
       lm_get_next_ec_value               Return event-counter value plus
                                          one
       lm_has_event_occurred              Determine whether event has
                                          occurred
       lm_increment_ec_value              Increment event-counter value
       lm_initialize_ec                   Prepare an eventcounter for its
                                          first use
       lm_initialize_sequencer            Set sequencer to zero
       lm_read_ec                         Read specified event counter
       lm_ticket_sequencer                Add 1 to sequencer and return
                                          value in variable
       lm_are_ec_values_equal             Compare two event-counter values

   Overview to Using Event Counters
       Event counters are one of the primary synchronization mechanism used
       in the DG/UX kernel (see also event_flags(3K)).  The DG/UX system's
       treatment of event counters and the related concept of a sequencer
       comes from work by Reed and Kanodia.  See the Communications of the
       ACM papers listed in the "Other Documents" section of the Preface to
       Programming in the DG/UX Environment for more technical background on
       event counters and sequencers.

       The event-counter synchronization mechanism uses two basic elements:
       event counters and events.  An event counter is simply a count of the
       number of times some condition of interest has happened.  You create
       an event counter by declaring a variable of event-counter type
       (lm_ec_type) and then initializing its count value to zero by calling
       lm_initialize_ec.

       Events are separate from event counters.  Event allow you to define
       "events" of interest by connecting an event counter with a critical
       value.  When the eventcount is equal to the critical value, the event
       is said to be "satisfied" and the kernel automatically awakens all
       LWPs waiting on the event.  You create an event by declaring a
       variable of event type (lm_event_type) and filling in the name of the
       event counter (pointer to its count address) and the critical value.
       Typically, you will define an event counter globally and create
       successive events from it.

       Typically, you will also want to wait for the event to occur once you
       have created it.  You do this by calling lm_await_events.  The
       lm_await_events routine actually allows you to suspend while waiting
       for any of a number of events supplied in an event list.  If one or
       more of the specified events is already satisfied when the await call
       is made, await returns immediately and the LWP continues execution.
       If none of the specified events is satisfied, the LWP enters the
       awaiting state where it does not compete for CPU resources.  Because
       a LWP doing a lm_await_events may suspend indefinitely, it should
       only hold locks while awaiting an event that can be counted on
       occurring in a reasonable time (perhaps a second or less).

       When one of the events is satisfied, the kernel will awaken the
       waiting LWP and pass it the index of the event that has occurred.
       The index identifies the event in the list that caused the await to
       be satisfied.  However, the event specified by the index is not
       necessarily the only event that has occurred in the list.  You may
       determine if other events in the list have occurred by calling the
       routine lm_has_event_occurred for each entry in the event list.  Note
       that if you want to wait until ALL of the desired events have
       occurred, you may need to do several calls to lm_await_events,
       reconstructing a shortened list of events each time.

       Frequently, the event you will want to create is the next occurrence
       of the condition, that is, the next increment of the event counter
       (however, if this is the case, also consider using an eventflag; see
       event_flags(3K)).  You can create such an event by: 1) calling
       lm_read_ec which reads the current count into an event value
       variable; and 2) calling lm_increment_ec which adds one to that count
       value--making a critical value equal to "the next occurrence."
       Alternatively, you can call lm_get_next_ec_value to perform these two
       steps in one indivisible step; it reads and returns an incremented
       count into an event value variable.

       Some part of your code will also have to advance the event counter
       each time the condition of interest occurs.  You advance the event
       counter by calling lm_advance_ec.  After incrementing the specified
       event counter, the advance operation checks to see whether the new
       value of the incremented event counter causes any events to be
       satisfied.  If the LWP associated with a satisfied event is still in
       the awaiting state, it is scheduled to run.  Because interrupts are
       one common condition of interest, interrupt service routines are
       frequently the ones calling lm_advance_ec.

       Because event counters are monotonically increasing values, they map
       very well into the normal concepts of clocks and times.  This allows
       clocks routines and timer routines to be based on the same event-
       counter mechanism.  A clock can be considered an event counter, and
       when the clock reaches a certain value an event is triggered.  The
       two routines lm_convert_clock_value_to_ec_value and
       lm_convert_ec_value_to_clock_value allow you to convert between clock
       and event-counter values.

       Because event counters are monotonically increasing values, they also
       provide a natural ordering of events.  This allows the event-counter
       mechanism to be extended to support sequencing using the concept of
       "sequencers."  Often simply waiting on an event is not enough; what
       is wanted is a way of ordering, or sequencing, the waiters on an
       event.  This is often the case when the event being awaited is access
       to a resource of some sort, such as a critical section of code or
       shared data.  Sequencers support such ordering.

       Sequencers, like event counters, are simply counters with values that
       increase in a monotonic fashion.  Like event counters, sequencers are
       declared and initialized (in sequencer's case, by calling
       lm_initialize_sequencer).  Sequencers order events by issuing
       sequential "tickets."  You get a ticket by calling
       lm_ticket_sequencer which atomically increments the current value of
       the sequencer and returns the new value.  Thus, each caller of the
       ticket operation gets a unique value and the values are ordered by
       the order in which the calls to ticket were made: the first caller
       will get 1, the second 2, and so on.  You create events using these
       ticket values and await them using lm_await_events.  Each LWP will
       see its event in turn--in the same order as the sequencer values.
       This is exactly the same as in any store where you "take a number for
       service."

       Event counters offer several advantages over the more simplistic
       synchronizations techniques used in most standard UNIX
       implementations.  First, because event counters actually count the
       number of occurrences of an event, you can tell if an event has
       already happened.  Thus, in a sense event counters remember previous
       events.  If code tries to wait on an event that has already happened
       (the event's critical value is less than the current count), the wait
       returns immediately because the event has been satisfied.  There is
       no danger of the waiting LWP pending forever as with the standard
       UNIX sleep and wakeup primitives.

       The lm_are_ec_values_equal routine for comparing event-counter values
       is provided for convenience.

       You must be careful of the order in which you perform the tasks
       involved in creating and awaiting an event lest you accidentally
       create an endless wait situation.  Specifically, if you start the I/O
       operation to be awaited before you create the event, the I/O may be
       logged before you get the event counter and the condition you create
       will be one count past the operation you started.  The best sequence
       for creating and awaiting events is: 1) create the event to be
       awaited; 2) start the I/O operation; 3) check the event; 4) if it is
       not satisfied (and you want to suspend until it is), start the await
       process.  The typical code sequence is as follows:
              dev_cird_build_scatter_gather_arrays(request_block_ptr);
              request_completion_event.name = &request_block_ptr->sync_io_ec;
              lm_get_next_ec_value(&request_block_ptr->sync_io_ec,
                                   &request_completion_event.value);
              status = dev_cird_start_command_list_request(request_block_ptr);
              if (status == OK)
                  {
                  lm_await_events(&request_completion_event,
                                  (int32_type)1,
                                  &result_index);
                  }

       If you use routines from this man page, you must allocate the space
       used by the event and event-counter instances (see the Constants and
       Data Structures subsection below).  Event counters may be allocated
       from global memory or allocated dynamically.  Event types are
       allocated dynamically, as needed.

   Constants and Data Structures
       This subsection describes constants and data structures defined in
       the include files cited in the SYNOPSIS section and used by the
       routines documented in this man page.

       Try to avoid dependencies on the specifics of these structures, such
       as size or location of fields, because these specifics may change in
       later releases of the software.  You can verify exact variable
       definitions in the appropriate include file.  The best way to avoid
       such dependencies is to use kernel-supplied routines to manipulate
       these structures.

       lm_event_type
              typedef struct
                 {
                 lm_ec_ptr_type     name;
                 lm_ec_value_type   value;
                 }
                 lm_event_type ;

       This structure defines an event, which is an event counter name and
       an event-counter value.  The event is said to occur or to be
       satisfied when the value of the event counter pointed to by the name
       field is greater than or equal to the value field.

   lm_add_to_ec_value
       This routine adds the given value to the specified event-counter
       value.  The specified 32-bit integer is added to the specified event-
       counter value.

   lm_advance_ec
       This routine performs an advance (by one) on the specified event
       counter.  Any LWPs awaiting on the new value of the event counter
       will be notified.

       The event counter is indivisibly incremented, and any LWPs awaiting
       on the new value are notified.  If a higher priority LWP becomes
       eligible to run as a result of the notification, it may be
       rescheduled.  Thus, your LWP may be preempted if you call this
       routine.

   lm_are_ec_values_equal
       This routine compares two event-counter values and returns TRUE if
       they are equal.

   lm_await_events
       This routine performs the await operation on one or more events.  The
       calling LWP will be suspended until at least one of the specified
       events is satisfied.

       If any of the events is satisfied at the time the call is made, the
       LWP is not suspended.  When the call returns, the list_index_ptr is
       set to the index of an event that is satisfied, but if more than one
       event is satisfied, no statement is made about which event will be
       indicated by list_index_ptr.

   lm_convert_clock_value_to_ec_value
       This routine converts a clock value into an event-counter value.
       Converting from clock value to event-counter value requires
       converting the 64-bit clock value to a 32-bit event-counter value.

       The number of bits to take from the high and low word of the clock
       value are defined in i_lm.h as LM_CLOCK_TO_EC_HIGH_BITS and
       LM_CLOCK_TO_EC_LOW_BITS.

   lm_convert_ec_value_to_clock_value
       This routine converts an event-counter value into a clock value.
       Conversion from event-counter value to clock value requires
       converting a 32-bit event-counter value to a 64-bit clock value.
       This routine uses the current time in calculating the high-order bits
       of the clock value; converting an event-counter value that is too far
       in the future or past will result in an incorrect result.  The
       permissible interval is defined by the value misc_clock_value_type
       variable lm_max_clock_ec_increment, and is approximately 72 hours.

       The number of bits to assign to the high and low word of the clock
       value are defined in i_lm.h as LM_CLOCK_TO_EC_HIGH_BITS and
       LM_CLOCK_TO_EC_LOW_BITS.

   lm_get_next_ec_value
       This routine indivisibly reads the specified event counter and
       returns its value plus one.

       The event counter is read indivisibly with respect to other
       processors and with respect to the executing processor's interrupt
       level.  The value is then increased by one, which is equal to the
       value that will be reached the next time the event counter is
       advanced.

   lm_has_event_occurred
       This routine determines whether the given event has occurred.

   lm_increment_ec_value
       This routine increments the specified event-counter value.  The
       routine simply takes the event-counter value passed in and increments
       it.  It does not cause any LWP to be awoken.

   lm_initialize_ec
       This routine initializes an event counter to zero.

   lm_initialize_sequencer
       This routine initializes a sequencer to zero.

   lm_read_ec
       This routine indivisibly reads the specified event counter and
       returns the value in the variable pointed to by ec_value_ptr.

       The event counter is read indivisibly with respect to other
       processors and with respect to the executing processor's interrupt
       level.

   lm_ticket_sequencer
       This routine indivisibly increments the value of the specified
       sequencer and returns the new value (that is, the value after the
       increment).

       The sequencer value is incremented and then read as an indivisible
       operation.

DIAGNOSTICS
   Return Value
       For lm_are_ec_values_equal:
              TRUE   The event-counter values are equal.
              FALSE  The event-counter values are not equal.

       For lm_has_event_occurred:
              TRUE   The event has been satisfied.
              FALSE  The event has not yet occurred.

       For the other routines: none.

   Errors
       None.

NOTES
       An older family of routines, whose names start with "vp_" is also
       supported.  The routines described here ("lm_") are more efficient
       and offer a slightly easier to use interface.  The use of the vp_
       routines is deprecated.

SEE ALSO
       system_clock(3K).
       event_flags(3K).
       Programming in the DG/UX Kernel Environment.


Licensed material--property of copyright holder(s)

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026