s6

Mirror/fork of https://skarnet.org/software/s6/
git clone https://ccx.te2000.cz/git/s6
Log | Files | Refs | README | LICENSE

ftrigr.html (11338B)


      1 <html>
      2   <head>
      3     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      4     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
      5     <meta http-equiv="Content-Language" content="en" />
      6     <title>s6: the ftrigr library interface</title>
      7     <meta name="Description" content="s6: the ftrigr library interface" />
      8     <meta name="Keywords" content="s6 ftrig notification subscriber listener libftrigr ftrigr library interface" />
      9     <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
     10   </head>
     11 <body>
     12 
     13 <p>
     14 <a href="index.html">libs6</a><br />
     15 <a href="../">s6</a><br />
     16 <a href="//skarnet.org/software/">Software</a><br />
     17 <a href="//skarnet.org/">skarnet.org</a>
     18 </p>
     19 
     20 <h1> The <tt>ftrigr</tt> library interface </h1>
     21 
     22 <p>
     23  The <tt>ftrigr</tt> library provides an API for listeners, i.e.
     24 programs that want to subscribe to fifodirs and be instantly
     25 notified when the proper sequence of events happens.
     26 </p>
     27 
     28 <h2> Programming </h2>
     29 
     30 <p>
     31  Check the <tt>s6/ftrigr.h</tt> header for the
     32 exact function prototypes.
     33 </p>
     34 
     35 <p>
     36  Make sure your application is not disturbed by children it doesn't
     37 know it has. This means paying some attention to the SIGCHLD handler,
     38 if any, and to the way you perform <tt>waitpid()</tt>s. The best
     39 practice is to use a
     40 <a href="//skarnet.org/software/skalibs/libstddjb/selfpipe.html">self-pipe</a>
     41 to handle SIGCHLD (as well as other signals the application needs to trap),
     42 and to <em>always</em> use <tt>wait_nohang()</tt> to reap children,
     43 simply ignoring pids you don't know.
     44 </p>
     45 
     46 <p>
     47  If your application has trouble handling unknown
     48 children, consider using an ftrigrd service. (And fix your application!)
     49 </p>
     50 
     51 <h3> A programming example </h3>
     52 
     53 <p>
     54  The <tt>src/pipe-tools/s6-ftrig-listen1.c</tt> and
     55 <tt>src/supervision/s6-svwait.c</tt> files in the s6 package,
     56 for instance, illustrate how to use the ftrigr library.
     57 </p>
     58 
     59 <a name="synctimed">
     60 <h3> Synchronous functions with a specified maximum execution time </h3>
     61 </a>
     62 
     63 <ul>
     64  <li> Synchronous functions take a <tt>tain_t const *</tt>
     65 (<em>deadline</em>) parameter and a <tt>tain_t *</tt> (<em>stamp</em>)
     66 parameter. Those are pointers to tain_t structures containing absolute times;
     67 the former represents a deadline (in most cases, this time will be in the
     68 future) and the latter must be an accurate enough timestamp. These
     69 structures can be filled using the <tt>tain_</tt> primitives declared in
     70 <a href="//skarnet.org/software/skalibs/libstddjb/tai.html">skalibs/tai.h</a>. </li>
     71  <li> ("Accurate enough" means that <strong>no blocking system call must have
     72 been made</strong> since the last time <em>stamp</em> was updated (by
     73 <tt>tain_now(&amp;stamp)</tt>). It's a good policy to always update
     74 <em>stamp</em> right after a (potentially) blocking system call like
     75 <tt>select()</tt> returns. And unless the application is extremely CPU-intensive
     76 (think calculus for physicists or astronomers) updating <em>stamp</em> more
     77 frequently is unnecessary.) </li>
     78  <li> If such a synchronous function still hasn't returned when the deadline
     79 occurs, then it will immediately return a failure code and set errno to ETIMEDOUT.
     80 It is possible to pass null pointers to the function instead of pointers to
     81 tain_t structures, in which case the function will never timeout. </li>
     82  <li> If a timeout occurs, the library does not guarantee proper interprocess
     83 communication later on; the application should either die, or at least close
     84 the communication channel and open a new one. </li>
     85  <li> If any waiting occurred, the <em>stamp</em> structure is automatically
     86 updated by the called function, so it always represents an accurate enough estimation
     87 of the current time. This allows the programmer to call several such functions
     88 in a sequence without modifying the <em>deadline</em> and <em>stamp</em>
     89 parameters: then the whole sequence is bound in execution time. </li>
     90  <li> This is a general safety mechanism implemented in
     91 <a href="//skarnet.org/software/skalibs/libunixonacid/">libunixonacid</a>:
     92 in interprocess communication, purely synchronous primitives are dangerous
     93 because they make the calling process rely on proper behaviour of the called
     94 process. Giving synchronous primitives the ability to timeout allows developers
     95 to write reliable programs even when interacting with software they have no
     96 control on. </li>
     97 </ul>
     98 
     99 
    100 <h3> Starting and ending a session </h3>
    101 
    102 <pre>
    103 ftrigr_t a = FTRIGR_ZERO ;
    104 tain_t deadline, stamp ;
    105 
    106 tain_now(&amp;stamp) ;
    107 tain_addsec(&amp;deadline, &amp;stamp, 2)
    108 
    109 // char const *path = FTRIGR_IPCPATH ;
    110 // ftrigr_start(&amp;a, path, &amp;deadline, &amp;stamp) ;
    111 ftrigr_startf(&amp;a, &amp;deadline, &amp;stamp) ;
    112 </pre>
    113 
    114 <p>
    115 <tt>ftrigr_start</tt> starts a session with an ftrigrd service listening on
    116 <em>path</em>. <br />
    117 <tt>ftrigr_startf</tt> starts a session with an ftrigrd process as a child
    118 (which is the simplest usage). <br />
    119 <tt>a</tt> is an ftrigr_t structure that must be declared in the stack and
    120 initialized to FTRIGR_ZERO.
    121 <tt>stamp</tt> must be an accurate enough timestamp. <br />
    122 If the session initialization fails, the function returns 0 and errno is set;
    123 else the function returns 1.
    124 </p>
    125 <p>
    126 If the absolute time <tt>deadline</tt> is reached and the function
    127 has not returned yet, it immediately returns 0 with errno set to ETIMEDOUT.
    128 
    129 Only local interprocess communications are involved; unless your system is
    130 heavily overloaded, the function should return near-instantly. One or two
    131 seconds of delay between <tt>stamp</tt> and <tt>deadline</tt> should be
    132 enough: if the function takes more than that to return, then there is a
    133 problem with the underlying processes.
    134 </p>
    135 
    136 <p>
    137  You can have more than one session open in parallel, by declaring
    138 several distinct <tt>ftrigr_t</tt> structures and calling
    139 <tt>ftrigr_startf</tt> (or <tt>ftrigr_start</tt>) more than once.
    140 However, this is useless, since one single session can handle
    141 virtually as many concurrent fifodirs as your application needs.
    142 </p>
    143 
    144 <pre>
    145 ftrigr_end(&amp;a) ;
    146 </pre>
    147 
    148 <p>
    149 <tt>ftrigr_end</tt> frees all the resources used by the session. The
    150 <tt>a</tt> structure is then reusable for another session.
    151 </p>
    152 
    153 <h3> Subscribing to a fifodir </h3>
    154 
    155 <pre>
    156 char const *path = "/var/lib/myservice/fifodir" ;
    157 char const *re = "a.*b|c*d" ;
    158 uint32_t options = 0 ;
    159 
    160 uint16_t id = ftrigr_subscribe (&amp;a, path, re, options, &amp;deadline, &amp;stamp) ;
    161 </pre>
    162 
    163 <p>
    164 <tt>ftrigr_subscribe</tt> instructs the
    165 <a href="s6-ftrigrd.html">s6-ftrigrd daemon</a>, related to the open
    166 session represented by the <tt>a</tt> structure, to subscribe to the
    167 <tt>path</tt> fifodir, and to notify the application when it receives
    168 a series of events that matches the <tt>re</tt> regexp.
    169 <tt>options</tt> can be 0 or FTRIGR_REPEAT. If it is 0, the daemon will
    170 automatically unsubscribe from <tt>path</tt> once <tt>re</tt> has been
    171 matched by a series of events. If it is FTRIGR_REPEAT, it will remain
    172 subscribed until told otherwise.
    173 </p>
    174 
    175 <p>
    176  <tt>ftrigr_subscribe()</tt> returns 0 and sets errno in case of failure, or
    177 a nonzero 16-bit number identifying the subscription in case of success.
    178 </p>
    179 
    180 <p>
    181 <tt>ftrigr_subscribe</tt> should return near-instantly, but if
    182 <em>deadline</em> is reached, it will return 0 ETIMEDOUT. If
    183 <tt>ftrigr_subscribe</tt> returns successfully, then the
    184 s6-ftrigrd daemon is guaranteed to be listening on <tt>path</tt>,
    185 and events can be sent without the risk of a race condition.
    186 </p>
    187 
    188 <h3> Synchronously waiting for events </h3>
    189 
    190 <pre>
    191 uint16_t list[1] ;
    192 unsigned int n = 1 ;
    193 char trigger ;
    194 list[0] = id ;
    195 
    196 // r = ftrigr_wait_and(&amp;a, list, n, &amp;deadline, &amp;stamp) ;
    197 r = ftrigr_wait_or(&amp;a, list, n, &amp;deadline, &amp;stamp, &amp;trigger) ;
    198 </pre>
    199 
    200 <p>
    201  <tt>ftrigr_wait_and()</tt> waits for <em>all</em> the <tt>n</tt> fifodirs
    202 whose ids are listed in <tt>list</tt> to receive an event. It returns -1
    203 in case of error or timeout, or a non-negative integer in case of success. <br />
    204  <tt>ftrigr_wait_or()</tt> waits for <em>one</em> of the <tt>n</tt> fifodirs
    205 whose ids are listed in <tt>list</tt> to receive an event. It returns -1
    206 in case of error or timeout; if it succeeds, the return value is the
    207 position in <tt>list</tt>, starting at 0, of the identifier that received
    208 an event; and <tt>trigger</tt> is set to the character that triggered that
    209 event, i.e. the last character of a sequence that matched the regular
    210 expression <tt>re</tt> used in the subscription.
    211 </p>
    212 
    213 <h3> Asynchronously waiting for events </h3>
    214 
    215 <p>
    216 <em> (from now on, the functions are listed with their prototypes instead
    217 of usage examples.) </em>
    218 </p>
    219 
    220 <pre>
    221 int ftrigr_fd (ftrigr_t const *a)
    222 </pre>
    223 
    224 <p>
    225  Returns a file descriptor to select on for reading. Do not
    226 <tt>read()</tt> it though.
    227 </p>
    228 
    229 <pre>
    230 int ftrigr_updateb (ftrigr_t *a)
    231 </pre>
    232 
    233 <p>
    234  Call this function whenever the fd checks readability: it will
    235 update <em>a</em>'s internal structures with information from the
    236 <a href="s6-ftrigrd.html">s6-ftrigrd</a> daemon. It returns -1 if an error
    237 occurs; in case of success, it returns the number of identifiers for
    238 which something happened.
    239 </p>
    240 
    241 <p>
    242  When <tt>ftrigr_updateb</tt> returns,
    243 <tt>genalloc_s(uint16_t, &amp;a-&gt;list)</tt> points to an array of
    244 <tt>genalloc_len(uint16_t, &amp;a-&gt;list)</tt> 16-bit unsigned
    245 integers. Those integers are ids waiting to be passed to
    246 <tt>ftrigr_check</tt> or <tt>ftrigr_checksa</tt>.
    247 The number of ids already acknowledged is stored in
    248 <tt>a-&gt;head</tt>, so the first unacknowledged id is
    249 <tt>genalloc_s(uint16_t, &amp;a-&gt;list)[a-&gt;head]</tt>.
    250 </p>
    251 
    252 <pre>
    253 int ftrigr_check (ftrigr_t *a, uint16_t id, char *what)
    254 </pre>
    255 
    256 <p>
    257  Checks whether an event happened to <em>id</em>. Use after a
    258 call to <tt>ftrigr_updateb()</tt>.
    259 </p>
    260 
    261 <ul>
    262  <li> If an error occurred, returns -1 and sets errno. The error
    263 number may have been transmitted from
    264 <a href="s6-ftrigrd.html">s6-ftrigrd</a>. </li>
    265  <li> If no notification happened yet, returns 0. </li>
    266  <li> If something happened, writes the character that triggered the
    267 latest notification into <em>what</em> and returns the number of
    268 times that an event happened to this identifier since the last
    269 call to <tt>ftrigr_check()</tt>. </li>
    270 </ul>
    271 
    272 <pre>
    273 int ftrigr_checksa (ftrigr_t *a, uint16_t id, stralloc *what)
    274 </pre>
    275 
    276 <p>
    277  Checks whether an event happened to <em>id</em>. Use after a
    278 call to <tt>ftrigr_update()</tt>, as an alternative to <tt>ftrigr_check()</tt>.
    279 </p>
    280 
    281 <ul>
    282  <li> If an error occurred, returns -1 and sets errno. The error
    283 number may have been transmitted from
    284 <a href="s6-ftrigrd.html">s6-ftrigrd</a>. </li>
    285  <li> If no notification happened yet, returns 0. </li>
    286  <li> If something happened, appends one character to the end of the <em>what</em>
    287 <a href="//skarnet.org/software/skalibs/libstddjb/stralloc.html">stralloc</a>
    288 for every time a notification was triggered since the last call
    289 to <tt>ftrigr_check()</tt>. Each character is the one that triggered
    290 a notification. The function then returns 1. </li>
    291 </ul>
    292 
    293 <pre>
    294 void ftrigr_ack (ftrigr_t *a, size_t n)
    295 </pre>
    296 
    297 <p>
    298  Acknowledges reading <em>n</em> ids from the id list updated by
    299 <tt>ftrigr_updateb</tt>.
    300 </p>
    301 
    302 <pre>
    303 int ftrigr_update (ftrigr_t *a)
    304 </pre>
    305 
    306 <p>
    307  Acknowledges all the pending ids (i.e. clears the stored id list)
    308 then calls <tt>ftrigr_updateb()</tt>.
    309 </p>
    310 
    311 </body>
    312 </html>