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(&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(&stamp) ; 107 tain_addsec(&deadline, &stamp, 2) 108 109 // char const *path = FTRIGR_IPCPATH ; 110 // ftrigr_start(&a, path, &deadline, &stamp) ; 111 ftrigr_startf(&a, &deadline, &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(&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 (&a, path, re, options, &deadline, &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(&a, list, n, &deadline, &stamp) ; 197 r = ftrigr_wait_or(&a, list, n, &deadline, &stamp, &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, &a->list)</tt> points to an array of 244 <tt>genalloc_len(uint16_t, &a->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->head</tt>, so the first unacknowledged id is 249 <tt>genalloc_s(uint16_t, &a->list)[a->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>