Lely core libraries  2.2.5
can_net.c
Go to the documentation of this file.
1 
24 #include "io2.h"
25 #include <lely/can/net.h>
26 #include <lely/io2/can_net.h>
27 #include <lely/io2/ctx.h>
28 #include <lely/libc/stdlib.h>
29 #if !LELY_NO_THREADS
30 #include <lely/libc/threads.h>
31 #endif
32 #include <lely/util/diag.h>
33 #include <lely/util/spscring.h>
34 #include <lely/util/time.h>
35 #include <lely/util/util.h>
36 
37 #include <assert.h>
38 
39 #ifndef LELY_IO_CAN_NET_TXLEN
44 #define LELY_IO_CAN_NET_TXLEN 1000
45 #endif
46 
47 #ifndef LELY_IO_CAN_NET_TXTIMEO
52 #define LELY_IO_CAN_NET_TXTIMEO 100
53 #endif
54 
55 static void io_can_net_svc_shutdown(struct io_svc *svc);
56 
57 // clang-format off
58 static const struct io_svc_vtbl io_can_net_svc_vtbl = {
59  NULL,
60  &io_can_net_svc_shutdown
61 };
62 // clang-format on
63 
65 struct io_can_net {
67  struct io_svc svc;
84  int txtimeo;
88  struct can_msg read_msg;
90  struct can_err read_err;
92  struct io_can_chan_read read;
94  int read_errc;
96  size_t read_errcnt;
98  int state;
100  struct can_msg write_msg;
102  struct io_can_chan_write write;
106  size_t write_errcnt;
108  struct spscring tx_ring;
110  struct can_msg *tx_buf;
112  size_t tx_errcnt;
113 #if !LELY_NO_THREADS
119 #endif
159  unsigned started : 1;
161  unsigned shutdown : 1;
163  unsigned wait_next_submitted : 1;
167  unsigned read_submitted : 1;
169  unsigned write_submitted : 1;
173  struct timespec next;
174 };
175 
176 static void io_can_net_wait_next_func(struct ev_task *task);
177 static void io_can_net_wait_confirm_func(struct ev_task *task);
178 static void io_can_net_read_func(struct ev_task *task);
179 static void io_can_net_write_func(struct ev_task *task);
180 
181 static int io_can_net_next_func(const struct timespec *tp, void *data);
182 static int io_can_net_send_func(const struct can_msg *msg, void *data);
183 
184 static void io_can_net_c_wait_func(struct spscring *ring, void *arg);
185 
186 static inline io_can_net_t *io_can_net_from_svc(const struct io_svc *svc);
187 
188 int io_can_net_do_wait(io_can_net_t *net);
189 void io_can_net_do_write(io_can_net_t *net);
190 
191 size_t io_can_net_do_abort_tasks(io_can_net_t *net);
192 
193 static void default_on_read_error_func(int errc, size_t errcnt, void *arg);
194 static void default_on_queue_error_func(int errc, size_t errcnt, void *arg);
195 static void default_on_write_error_func(int errc, size_t errcnt, void *arg);
196 static void default_on_can_state_func(int new_state, int old_state, void *arg);
197 static void default_on_can_error_func(int error, void *arg);
198 
199 void *
200 io_can_net_alloc(void)
201 {
202  void *ptr = aligned_alloc(_Alignof(io_can_net_t), sizeof(io_can_net_t));
203  if (!ptr)
204  set_errc(errno2c(errno));
205  return ptr;
206 }
207 
208 void
209 io_can_net_free(void *ptr)
210 {
211  aligned_free(ptr);
212 }
213 
214 io_can_net_t *
215 io_can_net_init(io_can_net_t *net, ev_exec_t *exec, io_timer_t *timer,
216  io_can_chan_t *chan, size_t txlen, int txtimeo)
217 {
218  assert(net);
219  assert(timer);
220  assert(chan);
221 
222  int errc = 0;
223 
224  if (!exec)
225  exec = io_can_chan_get_exec(chan);
226 
227  if (!txlen)
228  txlen = LELY_IO_CAN_NET_TXLEN;
229 
230  if (!txtimeo)
231  txtimeo = LELY_IO_CAN_NET_TXTIMEO;
232 
233  net->svc = (struct io_svc)IO_SVC_INIT(&io_can_net_svc_vtbl);
234  net->ctx = io_can_chan_get_ctx(chan);
235  assert(net->ctx);
236 
237  net->exec = exec;
238 
239  net->timer = timer;
240  if (!(net->tq = io_tqueue_create(net->timer, NULL))) {
241  errc = get_errc();
242  goto error_create_tq;
243  }
245  0, 0, NULL, &io_can_net_wait_next_func);
247  0, 0, NULL, &io_can_net_wait_confirm_func);
248  net->txtimeo = txtimeo;
249 
250  net->chan = chan;
251 
252  net->read_msg = (struct can_msg)CAN_MSG_INIT;
253  net->read_err = (struct can_err)CAN_ERR_INIT;
255  &net->read_msg, &net->read_err, NULL, NULL,
256  &io_can_net_read_func);
257  net->read_errc = 0;
258  net->read_errcnt = 0;
259 
260  net->state = CAN_STATE_ACTIVE;
261 
262  net->write_msg = (struct can_msg)CAN_MSG_INIT;
264  &net->write_msg, NULL, &io_can_net_write_func);
265  net->write_errc = 0;
266  net->write_errcnt = 0;
267 
268  spscring_init(&net->tx_ring, txlen);
269  net->tx_buf = calloc(txlen, sizeof(struct can_msg));
270  if (!net->tx_buf) {
271  errc = get_errc();
272  goto error_alloc_tx_buf;
273  }
274  net->tx_errcnt = 0;
275 
276 #if !LELY_NO_THREADS
277  if (mtx_init(&net->mtx, mtx_plain) != thrd_success) {
278  errc = get_errc();
279  goto error_init_mtx;
280  }
281 #endif
282 
283  net->on_read_error_func = &default_on_read_error_func;
284  net->on_read_error_arg = NULL;
285  net->on_queue_error_func = &default_on_queue_error_func;
286  net->on_queue_error_arg = NULL;
287  net->on_write_error_func = &default_on_write_error_func;
288  net->on_write_error_arg = NULL;
289  net->on_can_state_func = &default_on_can_state_func;
290  net->on_can_state_arg = NULL;
291  net->on_can_error_func = &default_on_can_error_func;
292  net->on_can_error_arg = NULL;
293 
294  net->started = 0;
295  net->shutdown = 0;
296  net->wait_next_submitted = 0;
297  net->wait_confirm_submitted = 0;
298  net->read_submitted = 0;
299  net->write_submitted = 0;
300 
301  if (!(net->net = can_net_create())) {
302  errc = get_errc();
303  goto error_create_net;
304  }
305  net->next = (struct timespec){ 0, 0 };
306 
307  // Initialize the CAN network clock with the current time.
308  if (io_can_net_set_time(net) == -1) {
309  errc = get_errc();
310  goto error_set_time;
311  }
312 
313  // Register the function to be invoked when the time at which the next
314  // timer triggers is updated.
315  can_net_set_next_func(net->net, &io_can_net_next_func, net);
316  // Register the function to be invoked when a CAN frame needs to be
317  // sent.
318  can_net_set_send_func(net->net, &io_can_net_send_func, net);
319 
320  io_ctx_insert(net->ctx, &net->svc);
321 
322  return net;
323 
324 error_set_time:
325  can_net_destroy(net->net);
326 error_create_net:
327 #if !LELY_NO_THREADS
328  mtx_destroy(&net->mtx);
329 error_init_mtx:
330 #endif
331  free(net->tx_buf);
332 error_alloc_tx_buf:
333  io_tqueue_destroy(net->tq);
334 error_create_tq:
335  set_errc(errc);
336  return NULL;
337 }
338 
339 void
340 io_can_net_fini(io_can_net_t *net)
341 {
342  assert(net);
343 
344  io_ctx_remove(net->ctx, &net->svc);
345  // Cancel all pending operations.
346  io_can_net_svc_shutdown(&net->svc);
347 
348 #if !LELY_NO_THREADS
349  int warning = 0;
350  mtx_lock(&net->mtx);
351  // If necessary, busy-wait until all submitted operations complete.
352  while (net->wait_next_submitted || net->wait_confirm_submitted
353  || net->read_submitted || net->write_submitted) {
354  if (io_can_net_do_abort_tasks(net))
355  continue;
356  mtx_unlock(&net->mtx);
357  if (!warning) {
358  warning = 1;
359  diag(DIAG_WARNING, 0,
360  "io_can_net_fini() invoked with pending operations");
361  }
362  thrd_yield();
363  mtx_lock(&net->mtx);
364  }
365  mtx_unlock(&net->mtx);
366 #endif
367 
368  can_net_destroy(net->net);
369 #if !LELY_NO_THREADS
370  mtx_destroy(&net->mtx);
371 #endif
372  free(net->tx_buf);
373  io_tqueue_destroy(net->tq);
374 }
375 
376 io_can_net_t *
378  size_t txlen, int txtimeo)
379 {
380  int errc = 0;
381 
382  io_can_net_t *net = io_can_net_alloc();
383  if (!net) {
384  errc = get_errc();
385  goto error_alloc;
386  }
387 
388  io_can_net_t *tmp =
389  io_can_net_init(net, exec, timer, chan, txlen, txtimeo);
390  if (!tmp) {
391  errc = get_errc();
392  goto error_init;
393  }
394  net = tmp;
395 
396  return net;
397 
398 error_init:
399  io_can_net_free(net);
400 error_alloc:
401  set_errc(errc);
402  return NULL;
403 }
404 
405 void
407 {
408  if (net) {
409  io_can_net_fini(net);
410  io_can_net_free(net);
411  }
412 }
413 
414 void
416 {
417  assert(net);
418 
419 #if !LELY_NO_THREADS
420  mtx_lock(&net->mtx);
421 #endif
422  if (!net->started && !net->shutdown) {
423  net->started = 1;
424 
425  // Start waiting for CAN frames to be put into the transmit
426  // queue.
427  io_can_net_do_wait(net);
428 
429  assert(!net->read_submitted);
430  net->read_submitted = 1;
431  // Start receiving CAN frames.
432  io_can_chan_submit_read(net->chan, &net->read);
433  }
434 #if !LELY_NO_THREADS
435  mtx_unlock(&net->mtx);
436 #endif
437 }
438 
439 io_ctx_t *
441 {
442  assert(net);
443 
444  return net->ctx;
445 }
446 
447 ev_exec_t *
449 {
450  assert(net);
451 
452  return net->exec;
453 }
454 
455 io_clock_t *
457 {
458  assert(net);
459 
461 }
462 
463 io_tqueue_t *
465 {
466  assert(net);
467 
468  return net->tq;
469 }
470 
471 void
473  io_can_net_on_error_func_t **pfunc, void **parg)
474 {
475  assert(net);
476 
477 #if !LELY_NO_THREADS
478  mtx_lock((mtx_t *)&net->mtx);
479 #endif
480  if (pfunc)
481  *pfunc = net->on_read_error_func;
482  if (parg)
483  *parg = net->on_read_error_arg;
484 #if !LELY_NO_THREADS
485  mtx_unlock((mtx_t *)&net->mtx);
486 #endif
487 }
488 
489 void
491  io_can_net_t *net, io_can_net_on_error_func_t *func, void *arg)
492 {
493  assert(net);
494 
495 #if !LELY_NO_THREADS
496  mtx_lock(&net->mtx);
497 #endif
498  net->on_read_error_func = func ? func : &default_on_read_error_func;
499  net->on_read_error_arg = func ? arg : NULL;
500 #if !LELY_NO_THREADS
501  mtx_unlock(&net->mtx);
502 #endif
503 }
504 
505 void
507  io_can_net_on_error_func_t **pfunc, void **parg)
508 {
509  assert(net);
510 
511 #if !LELY_NO_THREADS
512  mtx_lock((mtx_t *)&net->mtx);
513 #endif
514  if (pfunc)
515  *pfunc = net->on_queue_error_func;
516  if (parg)
517  *parg = net->on_queue_error_arg;
518 #if !LELY_NO_THREADS
519  mtx_unlock((mtx_t *)&net->mtx);
520 #endif
521 }
522 
523 void
525  io_can_net_t *net, io_can_net_on_error_func_t *func, void *arg)
526 {
527  assert(net);
528 
529 #if !LELY_NO_THREADS
530  mtx_lock(&net->mtx);
531 #endif
532  net->on_queue_error_func = func ? func : &default_on_queue_error_func;
533  net->on_queue_error_arg = func ? arg : NULL;
534 #if !LELY_NO_THREADS
535  mtx_unlock(&net->mtx);
536 #endif
537 }
538 
539 void
541  io_can_net_on_error_func_t **pfunc, void **parg)
542 {
543  assert(net);
544 
545 #if !LELY_NO_THREADS
546  mtx_lock((mtx_t *)&net->mtx);
547 #endif
548  if (pfunc)
549  *pfunc = net->on_write_error_func;
550  if (parg)
551  *parg = net->on_write_error_arg;
552 #if !LELY_NO_THREADS
553  mtx_unlock((mtx_t *)&net->mtx);
554 #endif
555 }
556 
557 void
559  io_can_net_t *net, io_can_net_on_error_func_t *func, void *arg)
560 {
561  assert(net);
562 
563 #if !LELY_NO_THREADS
564  mtx_lock(&net->mtx);
565 #endif
566  net->on_write_error_func = func ? func : &default_on_write_error_func;
567  net->on_write_error_arg = func ? arg : NULL;
568 #if !LELY_NO_THREADS
569  mtx_unlock(&net->mtx);
570 #endif
571 }
572 
573 void
575  io_can_net_on_can_state_func_t **pfunc, void **parg)
576 {
577  assert(net);
578 
579 #if !LELY_NO_THREADS
580  mtx_lock((mtx_t *)&net->mtx);
581 #endif
582  if (pfunc)
583  *pfunc = net->on_can_state_func;
584  if (parg)
585  *parg = net->on_can_state_arg;
586 #if !LELY_NO_THREADS
587  mtx_unlock((mtx_t *)&net->mtx);
588 #endif
589 }
590 
591 void
593  io_can_net_on_can_state_func_t *func, void *arg)
594 {
595  assert(net);
596 
597 #if !LELY_NO_THREADS
598  mtx_lock(&net->mtx);
599 #endif
600  net->on_can_state_func = func ? func : &default_on_can_state_func;
601  net->on_can_state_arg = func ? arg : NULL;
602 #if !LELY_NO_THREADS
603  mtx_unlock(&net->mtx);
604 #endif
605 }
606 
607 void
609  io_can_net_on_can_error_func_t **pfunc, void **parg)
610 {
611  assert(net);
612 
613 #if !LELY_NO_THREADS
614  mtx_lock((mtx_t *)&net->mtx);
615 #endif
616  if (pfunc)
617  *pfunc = net->on_can_error_func;
618  if (parg)
619  *parg = net->on_can_error_arg;
620 #if !LELY_NO_THREADS
621  mtx_unlock((mtx_t *)&net->mtx);
622 #endif
623 }
624 
625 void
627  io_can_net_on_can_error_func_t *func, void *arg)
628 {
629  assert(net);
630 
631 #if !LELY_NO_THREADS
632  mtx_lock(&net->mtx);
633 #endif
634  net->on_can_error_func = func ? func : &default_on_can_error_func;
635  net->on_can_error_arg = func ? arg : NULL;
636 #if !LELY_NO_THREADS
637  mtx_unlock(&net->mtx);
638 #endif
639 }
640 
641 int
643 {
644 #if LELY_NO_THREADS
645  (void)net;
646 
647  return 0;
648 #else
649  assert(net);
650 
651  return mtx_lock(&net->mtx);
652 #endif
653 }
654 
655 int
657 {
658 #if LELY_NO_THREADS
659  (void)net;
660 
661  return 0;
662 #else
663  assert(net);
664 
665  return mtx_unlock(&net->mtx);
666 #endif
667  assert(net);
668 }
669 
670 can_net_t *
672 {
673  assert(net);
674 
675  return net->net;
676 }
677 
678 int
680 {
681  struct timespec now = { 0, 0 };
682  if (io_clock_gettime(io_can_net_get_clock(net), &now) == -1)
683  return -1;
684  return can_net_set_time(io_can_net_get_net(net), &now);
685 }
686 
687 static void
688 io_can_net_svc_shutdown(struct io_svc *svc)
689 {
690  io_can_net_t *net = io_can_net_from_svc(svc);
691 
692 #if !LELY_NO_THREADS
693  mtx_lock(&net->mtx);
694 #endif
695  int shutdown = !net->shutdown;
696  net->shutdown = 1;
697 #if !LELY_NO_THREADS
698  mtx_unlock(&net->mtx);
699 #endif
700 
701  if (shutdown)
703 }
704 
705 static void
706 io_can_net_wait_next_func(struct ev_task *task)
707 {
708  assert(task);
709  struct io_tqueue_wait *wait_next = io_tqueue_wait_from_task(task);
710  io_can_net_t *net = structof(wait_next, io_can_net_t, wait_next);
711  assert(net->wait_next_submitted);
712 
713 #if !LELY_NO_THREADS
714  mtx_lock(&net->mtx);
715 #endif
716 
717  // Update the time of the CAN network interface.
718  io_can_net_set_time(net);
719 
720  // Check if the next timeout is in the future and another wait operation
721  // needs to be submitted.
722  int submit_wait_next = 0;
723  if (!net->shutdown) {
724  struct timespec now = { 0, 0 };
725  can_net_get_time(net->net, &now);
726  if (timespec_cmp(&now, &net->next) < 0) {
727  net->wait_next.value = net->next;
728  submit_wait_next = 1;
729  }
730  }
731  net->wait_next_submitted = submit_wait_next;
732 
733 #if !LELY_NO_THREADS
734  mtx_unlock(&net->mtx);
735 #endif
736 
737  if (submit_wait_next)
738  io_tqueue_submit_wait(net->tq, &net->wait_next);
739 }
740 
741 static void
742 io_can_net_wait_confirm_func(struct ev_task *task)
743 {
744  assert(task);
745  struct io_tqueue_wait *wait_confirm = io_tqueue_wait_from_task(task);
746  io_can_net_t *net = structof(wait_confirm, io_can_net_t, wait_confirm);
747  assert(net->txtimeo >= 0);
748  assert(net->wait_confirm_submitted);
749 
750 #if !LELY_NO_THREADS
751  mtx_lock(&net->mtx);
752 #endif
753  net->wait_confirm_submitted = 0;
754 #if !LELY_NO_THREADS
755  mtx_unlock(&net->mtx);
756 #endif
757 
758  // No confirmation message was received; cancel the ongoing write
759  // operation.
760  io_can_chan_cancel_write(net->chan, &net->write);
761 }
762 
763 static void
764 io_can_net_read_func(struct ev_task *task)
765 {
766  assert(task);
768  io_can_net_t *net = structof(read, io_can_net_t, read);
769 
770 #if !LELY_NO_THREADS
771  mtx_lock(&net->mtx);
772 #endif
773 
774  if (read->r.errc && errc2num(read->r.errc) != ERRNUM_CANCELED) {
775  net->read_errcnt += net->read_errcnt < SIZE_MAX;
776  if (read->r.errc != net->read_errc) {
777  net->read_errc = read->r.errc;
778  // Only invoke the callback for unique read errors.
779  assert(net->on_read_error_func);
780  net->on_read_error_func(net->read_errc, net->read_errc,
781  net->on_read_error_arg);
782  }
783  } else if (!read->r.errc && net->read_errc) {
784  assert(net->on_read_error_func);
785  net->on_read_error_func(
786  0, net->read_errc, net->on_read_error_arg);
787  net->read_errc = 0;
788  net->read_errcnt = 0;
789  }
790 
791  if (read->r.result == 1) {
792  // Update the internal clock before processing the incoming CAN
793  // frame.
794  io_can_net_set_time(net);
795  can_net_recv(net->net, &net->read_msg);
796  } else if (read->r.result == 0) {
797  if (net->read_err.state != net->state) {
798  int new_state = net->read_err.state;
799  int old_state = net->state;
800  net->state = net->read_err.state;
801 
802  if (old_state == CAN_STATE_BUSOFF)
803  // Cancel the ongoing write operation if we just
804  // recovered from bus off.
806  net->chan, &net->write);
807 
808  assert(net->on_can_state_func);
809  net->on_can_state_func(new_state, old_state,
810  net->on_can_state_arg);
811  }
812 
813  if (net->read_err.error) {
814  assert(net->on_can_error_func);
815  net->on_can_error_func(net->read_err.error,
816  net->on_can_error_arg);
817  }
818  }
819 
820  int submit_read = net->read_submitted = !net->shutdown;
821 
822 #if !LELY_NO_THREADS
823  mtx_unlock(&net->mtx);
824 #endif
825 
826  if (submit_read)
827  io_can_chan_submit_read(net->chan, &net->read);
828 }
829 
830 static void
831 io_can_net_write_func(struct ev_task *task)
832 {
833  assert(task);
835  io_can_net_t *net = structof(write, io_can_net_t, write);
836 
837 #if !LELY_NO_THREADS
838  mtx_lock(&net->mtx);
839 #endif
840 
841  if (write->errc) {
842  net->write_errcnt += net->write_errcnt < SIZE_MAX;
843  if (write->errc != net->write_errc) {
844  net->write_errc = write->errc;
845  // Only invoke the callback for unique write errors.
847  net->write_errc,
848  net->on_write_error_arg);
849  }
850  } else if (net->write_errc) {
851  assert(net->on_write_error_func);
852  net->on_write_error_func(
853  0, net->write_errc, net->on_write_error_arg);
854  net->write_errc = 0;
855  net->write_errcnt = 0;
856  }
857 
858  // Remove the frame from the transmit queue, unless the write operation
859  // was canceled, in which we discard the entire queue.
860  assert(spscring_c_capacity(&net->tx_ring) >= 1);
861  size_t n = 1;
862  if (errc2num(write->errc) == ERRNUM_CANCELED) {
863  n = spscring_c_capacity(&net->tx_ring);
864  // Track the number of dropped frames. The first frame has
865  // already been accounted for.
866  net->write_errcnt += n - 1;
867  }
868  spscring_c_commit(&net->tx_ring, n);
869 
870  // Stop the timeout after receiving a write confirmation (or write
871  // error).
872  if (net->wait_confirm_submitted
873  && io_tqueue_abort_wait(net->tq, &net->wait_confirm))
874  net->wait_confirm_submitted = 0;
875 
876  // Write the next frame, if available.
877  net->write_submitted = 0;
878  if (!net->shutdown && !io_can_net_do_wait(net))
879  io_can_net_do_write(net);
880 
881 #if !LELY_NO_THREADS
882  mtx_unlock(&net->mtx);
883 #endif
884 }
885 
886 static int
887 io_can_net_next_func(const struct timespec *tp, void *data)
888 {
889  assert(tp);
890  io_can_net_t *net = data;
891  assert(net);
892 
893  // Ignore calls that do not change the next timeout.
894  if (!timespec_cmp(&net->next, tp))
895  return 0;
896 
897  // In case io_can_net_wait_next_func() is currently running, store the
898  // time for the next earliest timeout so io_can_net_wait_next_func() can
899  // re-submit the wait operation.
900  net->next = *tp;
901 
902  if (net->shutdown)
903  return 0;
904 
905  // Re-submit the wait operation with the new timeout, but only if we can
906  // be sure io_can_net_wait_next_func() is not currently running.
907  if (!net->wait_next_submitted
908  || io_tqueue_abort_wait(net->tq, &net->wait_next)) {
909  net->wait_next_submitted = 1;
910  net->wait_next.value = *tp;
911  io_tqueue_submit_wait(net->tq, &net->wait_next);
912  }
913 
914  return 0;
915 }
916 
917 static int
918 io_can_net_send_func(const struct can_msg *msg, void *data)
919 {
920  assert(msg);
921  io_can_net_t *net = data;
922  assert(net);
923 
924  size_t n = 1;
925  size_t i = spscring_p_alloc(&net->tx_ring, &n);
926  if (n) {
927  net->tx_buf[i] = *msg;
928  spscring_p_commit(&net->tx_ring, n);
929  if (net->tx_errcnt) {
930  assert(net->on_queue_error_func);
931  net->on_queue_error_func(0, net->tx_errcnt,
932  net->on_queue_error_arg);
933  net->tx_errcnt = 0;
934  }
935  return 0;
936  } else {
938  net->tx_errcnt += net->tx_errcnt < SIZE_MAX;
939  if (net->tx_errcnt == 1) {
940  // Only invoke the callback for the first transmission
941  // error.
942  assert(net->on_queue_error_func);
944  net->on_queue_error_arg);
945  }
946  return -1;
947  }
948 }
949 
950 static void
951 io_can_net_c_wait_func(struct spscring *ring, void *arg)
952 {
953  (void)ring;
954  io_can_net_t *net = arg;
955  assert(net);
956 
957  // A frame was just added to the transmit queue; try to send it.
958  if (!io_can_net_do_wait(net))
959  io_can_net_do_write(net);
960 }
961 
962 static inline io_can_net_t *
963 io_can_net_from_svc(const struct io_svc *svc)
964 {
965  assert(svc);
966 
967  return structof(svc, io_can_net_t, svc);
968 }
969 
970 int
971 io_can_net_do_wait(io_can_net_t *net)
972 {
973  assert(net);
974 
975  // Wait for next frame to become available.
976  // clang-format off
978  &net->tx_ring, 1, &io_can_net_c_wait_func, net))
979  // clang-format on
980  return 1;
981 
982  // Extract the frame from the transmit queue.
983  size_t n = 1;
984  size_t i = spscring_c_alloc(&net->tx_ring, &n);
985  assert(n == 1);
986  net->write_msg = net->tx_buf[i];
987 
988  return 0;
989 }
990 
991 void
992 io_can_net_do_write(io_can_net_t *net)
993 {
994  assert(net);
995  assert(spscring_c_capacity(&net->tx_ring) >= 1);
996  assert(!net->write_submitted);
997 
998  // Send the frame.
999  net->write_submitted = 1;
1000  io_can_chan_submit_write(net->chan, &net->write);
1001 
1002  // Register a timeout for the write confirmation, if necessary.
1003  if (net->txtimeo >= 0
1004  && (!net->wait_confirm_submitted
1005  || io_tqueue_abort_wait(net->tq,
1006  &net->wait_confirm))) {
1007  net->wait_confirm_submitted = 1;
1009  &net->wait_confirm.value);
1011  io_tqueue_submit_wait(net->tq, &net->wait_confirm);
1012  }
1013 }
1014 
1015 size_t
1016 io_can_net_do_abort_tasks(io_can_net_t *net)
1017 {
1018  assert(net);
1019 
1020  size_t n = 0;
1021 
1022  if (net->wait_next_submitted
1023  && io_tqueue_abort_wait(net->tq, &net->wait_next)) {
1024  net->wait_next_submitted = 0;
1025  n++;
1026  }
1027 
1028  if (net->wait_confirm_submitted
1029  && io_tqueue_abort_wait(net->tq, &net->wait_confirm)) {
1030  net->wait_confirm_submitted = 0;
1031  n++;
1032  }
1033 
1034  if (net->read_submitted
1035  && io_can_chan_abort_read(net->chan, &net->read)) {
1036  net->read_submitted = 0;
1037  n++;
1038  }
1039 
1040  if (net->write_submitted
1041  && io_can_chan_abort_write(net->chan, &net->write)) {
1042  net->write_submitted = 0;
1043  n++;
1044  }
1045 
1046  return 0;
1047 }
1048 
1049 static void
1050 default_on_read_error_func(int errc, size_t errcnt, void *arg)
1051 {
1052  (void)arg;
1053 
1054  if (errc)
1055  diag(DIAG_WARNING, errc, "error reading CAN frame");
1056  else
1057  diag(DIAG_INFO, 0,
1058  "CAN frame successfully read after %zu read error%s",
1059  errcnt, errcnt > 1 ? "s" : "");
1060 }
1061 
1062 static void
1063 default_on_queue_error_func(int errc, size_t errcnt, void *arg)
1064 {
1065  (void)arg;
1066 
1067  if (errc)
1069  "CAN transmit queue full; dropping frame");
1070  else
1071  diag(DIAG_INFO, 0,
1072  "CAN frame successfully queued after dropping %zd frame%s",
1073  errcnt, errcnt > 1 ? "s" : "");
1074 }
1075 
1076 static void
1077 default_on_write_error_func(int errc, size_t errcnt, void *arg)
1078 {
1079  (void)arg;
1080 
1081  if (errc)
1082  diag(DIAG_WARNING, errc, "error writing CAN frame");
1083  else
1084  diag(DIAG_INFO, 0,
1085  "CAN frame successfully written after %zu write error%s",
1086  errcnt, errcnt > 1 ? "s" : "");
1087 }
1088 
1089 static void
1090 default_on_can_state_func(int new_state, int old_state, void *arg)
1091 {
1092  (void)old_state;
1093  (void)arg;
1094 
1095  switch (new_state) {
1096  case CAN_STATE_ACTIVE:
1097  diag(DIAG_INFO, 0, "CAN bus is in the error active state");
1098  break;
1099  case CAN_STATE_PASSIVE:
1100  diag(DIAG_INFO, 0, "CAN bus is in the error passive state");
1101  break;
1102  case CAN_STATE_BUSOFF:
1103  diag(DIAG_WARNING, 0, "CAN bus is in the bus off state");
1104  break;
1105  case CAN_STATE_SLEEPING:
1106  diag(DIAG_INFO, 0, "CAN interface is in sleep mode");
1107  break;
1108  case CAN_STATE_STOPPED:
1109  diag(DIAG_WARNING, 0, "CAN interface is stopped");
1110  break;
1111  }
1112 }
1113 
1114 static void
1115 default_on_can_error_func(int error, void *arg)
1116 {
1117  (void)arg;
1118 
1119  if (error & CAN_ERROR_BIT)
1120  diag(DIAG_WARNING, 0, "single bit error detected on CAN bus");
1121  if (error & CAN_ERROR_STUFF)
1122  diag(DIAG_WARNING, 0, "bit stuffing error detected on CAN bus");
1123  if (error & CAN_ERROR_CRC)
1124  diag(DIAG_WARNING, 0, "CRC sequence error detected on CAN bus");
1125  if (error & CAN_ERROR_FORM)
1126  diag(DIAG_WARNING, 0, "form error detected on CAN bus");
1127  if (error & CAN_ERROR_ACK)
1128  diag(DIAG_WARNING, 0,
1129  "acknowledgment error detected on CAN bus");
1130  if (error & CAN_ERROR_OTHER)
1131  diag(DIAG_WARNING, 0,
1132  "one or more unknown errors detected on CAN bus");
1133 }
@ CAN_ERROR_FORM
A form error.
Definition: err.h:50
@ CAN_ERROR_BIT
A single bit error.
Definition: err.h:44
@ CAN_ERROR_STUFF
A bit stuffing error.
Definition: err.h:46
@ CAN_ERROR_ACK
An acknowledgment error.
Definition: err.h:52
@ CAN_ERROR_CRC
A CRC sequence error.
Definition: err.h:48
@ CAN_ERROR_OTHER
One or more other errors.
Definition: err.h:54
@ CAN_STATE_BUSOFF
The bus off state (TX/RX error count >= 256).
Definition: err.h:34
@ CAN_STATE_SLEEPING
The device is in sleep mode.
Definition: err.h:36
@ CAN_STATE_PASSIVE
The error passive state (TX/RX error count < 256).
Definition: err.h:32
@ CAN_STATE_STOPPED
The device is stopped.
Definition: err.h:38
@ CAN_STATE_ACTIVE
The error active state (TX/RX error count < 128).
Definition: err.h:30
#define CAN_MSG_INIT
The static initializer for can_msg.
Definition: msg.h:113
void io_can_net_set_on_read_error_func(io_can_net_t *net, io_can_net_on_error_func_t *func, void *arg)
Sets the function invoked when a new CAN frame read error occurs, or when a read operation completes ...
Definition: can_net.c:490
void io_can_net_set_on_can_state_func(io_can_net_t *net, io_can_net_on_can_state_func_t *func, void *arg)
Sets the function to be invoked when a CAN bus state change is detected.
Definition: can_net.c:592
io_ctx_t * io_can_net_get_ctx(const io_can_net_t *net)
Returns a pointer to the I/O context with which the CAN network interface is registered.
Definition: can_net.c:440
io_can_net_t * io_can_net_create(ev_exec_t *exec, io_timer_t *timer, io_can_chan_t *chan, size_t txlen, int txtimeo)
Creates a new CAN network interface.
Definition: can_net.c:377
void io_can_net_get_on_read_error_func(const io_can_net_t *net, io_can_net_on_error_func_t **pfunc, void **parg)
Retrieves the function invoked when a new CAN frame read error occurs, or when a read operation compl...
Definition: can_net.c:472
io_tqueue_t * io_can_net_get_tqueue(const io_can_net_t *net)
Returns a pointer to the internal timer queue of a CAN network interface.
Definition: can_net.c:464
void io_can_net_start(io_can_net_t *net)
Starts a CAN network interface and begins processing CAN frames.
Definition: can_net.c:415
int io_can_net_unlock(io_can_net_t *net)
Unlocks the mutex protecting the CAN network interface.
Definition: can_net.c:656
#define LELY_IO_CAN_NET_TXTIMEO
The default timeout (in milliseconds) of a CAN network interface when waiting for a CAN frame write c...
Definition: can_net.c:52
void io_can_net_set_on_queue_error_func(io_can_net_t *net, io_can_net_on_error_func_t *func, void *arg)
Sets the function invoked when a CAN frame is dropped because the transmit queue is full,...
Definition: can_net.c:524
can_net_t * io_can_net_get_net(const io_can_net_t *net)
Returns a pointer to the internal interface of a CAN network interface.
Definition: can_net.c:671
void io_can_net_get_on_write_error_func(const io_can_net_t *net, io_can_net_on_error_func_t **pfunc, void **parg)
Retrieves the function invoked when a new CAN frame write error occurs, or when a write operation com...
Definition: can_net.c:540
void io_can_net_get_on_queue_error_func(const io_can_net_t *net, io_can_net_on_error_func_t **pfunc, void **parg)
Retrieves the function invoked when a CAN frame is dropped because the transmit queue is full,...
Definition: can_net.c:506
void io_can_net_get_on_can_state_func(const io_can_net_t *net, io_can_net_on_can_state_func_t **pfunc, void **parg)
Retrieves the function invoked when a CAN bus state change is detected.
Definition: can_net.c:574
int io_can_net_set_time(io_can_net_t *net)
Updates the CAN network time.
Definition: can_net.c:679
void io_can_net_destroy(io_can_net_t *net)
Destroys a CAN network interface.
Definition: can_net.c:406
void io_can_net_set_on_can_error_func(io_can_net_t *net, io_can_net_on_can_error_func_t *func, void *arg)
Sets the function to be invoked when a CAN bus error is detected.
Definition: can_net.c:626
void io_can_net_get_on_can_error_func(const io_can_net_t *net, io_can_net_on_can_error_func_t **pfunc, void **parg)
Retrieves the function invoked when a CAN bus error is detected.
Definition: can_net.c:608
io_clock_t * io_can_net_get_clock(const io_can_net_t *net)
Returns a pointer to the clock used by the CAN network interface.
Definition: can_net.c:456
ev_exec_t * io_can_net_get_exec(const io_can_net_t *net)
Returns a pointer to the executor used by the CAN network interface to execute asynchronous tasks.
Definition: can_net.c:448
#define LELY_IO_CAN_NET_TXLEN
The default length (in number of CAN frames) of the user-space transmit queue of a CAN network interf...
Definition: can_net.c:44
int io_can_net_lock(io_can_net_t *net)
Locks the mutex protecting the CAN network interface.
Definition: can_net.c:642
void io_can_net_set_on_write_error_func(io_can_net_t *net, io_can_net_on_error_func_t *func, void *arg)
Sets the function invoked when a new CAN frame write error occurs, or when a write operation complete...
Definition: can_net.c:558
This header file is part of the I/O library; it contains the CAN network interface declarations.
void io_can_net_on_can_state_func_t(int new_state, int old_state, void *arg)
The type of function invoked when a CAN bus state change is detected by a CAN network interface.
Definition: can_net.h:80
void io_can_net_on_error_func_t(int errc, size_t errcnt, void *arg)
The type of function invoked when an error occurs during a CAN network interface operations,...
Definition: can_net.h:62
void io_can_net_on_can_error_func_t(int error, void *arg)
The type of function invoked when a CAN bus error is detected by an CAN network interface.
Definition: can_net.h:95
int io_clock_gettime(const io_clock_t *clock, struct timespec *tp)
Obtains the current time value of the specified clock.
Definition: clock.h:96
const struct io_clock_vtbl *const io_clock_t
An abstract clock.
Definition: clock.h:36
This header file is part of the I/O library; it contains the I/O context and service declarations.
void io_ctx_insert(io_ctx_t *ctx, struct io_svc *svc)
Registers an I/O service with an I/O context.
Definition: ctx.c:121
#define IO_SVC_INIT(vptr)
The static initializer for io_svc.
Definition: ctx.h:57
void io_ctx_remove(io_ctx_t *ctx, struct io_svc *svc)
Unregisters an I/O service with an I/O context.
Definition: ctx.c:136
This header file is part of the utilities library; it contains the diagnostic declarations.
@ DIAG_WARNING
A warning.
Definition: diag.h:47
@ DIAG_INFO
An informational message.
Definition: diag.h:45
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:156
errnum_t errc2num(int errc)
Transforms a native error code to a platform-independent error number.
Definition: errnum.c:310
@ ERRNUM_AGAIN
Resource unavailable, try again.
Definition: errnum.h:86
@ ERRNUM_CANCELED
Operation canceled.
Definition: errnum.h:96
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:947
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
#define _Alignof(x)
Specifies the alignment requirement of the declared object or member.
Definition: features.h:196
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition: ev.h:29
struct io_can_chan_write * io_can_chan_write_from_task(struct ev_task *task)
Obtains a pointer to a CAN channel write operation from a pointer to its completion task.
Definition: can.c:97
static io_ctx_t * io_can_chan_get_ctx(const io_can_chan_t *chan)
Definition: can.h:445
const struct io_can_chan_vtbl *const io_can_chan_t
An abstract CAN channel.
Definition: can.h:59
static size_t io_can_chan_abort_write(io_can_chan_t *chan, struct io_can_chan_write *write)
Aborts the specified CAN channel write operation if it is pending.
Definition: can.h:524
struct io_can_chan_read * io_can_chan_read_from_task(struct ev_task *task)
Obtains a pointer to a CAN channel read operation from a pointer to its completion task.
Definition: can.c:91
static size_t io_can_chan_abort_read(io_can_chan_t *chan, struct io_can_chan_read *read)
Aborts the specified CAN channel read operation if it is pending.
Definition: can.h:500
void io_can_chan_submit_write(io_can_chan_t *chan, struct io_can_chan_write *write)
Submits a write operation to a CAN channel.
Definition: can.h:512
void io_can_chan_submit_read(io_can_chan_t *chan, struct io_can_chan_read *read)
Submits a read operation to a CAN channel.
Definition: can.h:488
#define IO_CAN_CHAN_WRITE_INIT(msg, exec, func)
The static initializer for io_can_chan_write.
Definition: can.h:130
#define IO_CAN_CHAN_READ_INIT(msg, err, tp, exec, func)
The static initializer for io_can_chan_read.
Definition: can.h:104
static ev_exec_t * io_can_chan_get_exec(const io_can_chan_t *chan)
Definition: can.h:451
static size_t io_can_chan_cancel_write(io_can_chan_t *chan, struct io_can_chan_write *write)
Cancels the specified CAN channel write operation if it is pending.
Definition: can.h:518
const struct io_timer_vtbl *const io_timer_t
An abstract timer.
Definition: timer.h:38
io_clock_t * io_timer_get_clock(const io_timer_t *timer)
Returns a pointer to the clock used by the timer.
Definition: timer.h:238
This is the public header file of the utilities library.
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
Definition: util.h:93
#define CAN_ERR_INIT
The static initializer for a can_err struct.
Definition: err.h:43
This header file is part of the CAN library; it contains the CAN network interface declarations.
void can_net_get_time(const can_net_t *net, struct timespec *tp)
Retrieves the current time of a CAN network interface.
Definition: net.c:204
void can_net_set_send_func(can_net_t *net, can_send_func_t *func, void *data)
Sets the callback function used to send CAN frames from a network interface.
Definition: net.c:334
can_net_t * can_net_create(void)
Creates a new CAN network interface.
Definition: net.c:170
void can_net_destroy(can_net_t *net)
Destroys a CAN network interface.
Definition: net.c:195
void can_net_set_next_func(can_net_t *net, can_timer_func_t *func, void *data)
Sets the callback function invoked when the time at which the next CAN timer triggers is updated.
Definition: net.c:269
int can_net_recv(can_net_t *net, const struct can_msg *msg)
Receives a CAN frame with a network interface and processes it with the corresponding receiver(s).
Definition: net.c:278
int can_net_set_time(can_net_t *net, const struct timespec *tp)
Sets the current time of a CAN network interface.
Definition: net.c:213
This header file is part of the utilities library; it contains the single-producer,...
size_t spscring_c_alloc(struct spscring *ring, size_t *psize)
Allocates a consecutive range of indices, including wrapping, in a single-producer,...
Definition: spscring.c:262
int spscring_c_submit_wait(struct spscring *ring, size_t size, void(*func)(struct spscring *ring, void *arg), void *arg)
Checks if the requested range of indices, including wrapping, in a single-producer,...
Definition: spscring.c:327
size_t spscring_p_commit(struct spscring *ring, size_t size)
Makes the specified number of indices available to a consumer and, if this satisfies a wait operation...
Definition: spscring.c:138
size_t spscring_c_commit(struct spscring *ring, size_t size)
Makes the specified number of indices available to a producer and, if this satisfies a wait operation...
Definition: spscring.c:302
size_t spscring_c_capacity(struct spscring *ring)
Returns the total capacity available for a consumer in a single-producer single-consumer ring buffer,...
Definition: spscring.c:229
int spscring_c_abort_wait(struct spscring *ring)
Aborts a wait operation previously registered with spscring_c_submit_wait().
Definition: spscring.c:368
void spscring_init(struct spscring *ring, size_t size)
Initializes a single-producer, single-consumer ring buffer with the specified size.
Definition: spscring.c:47
size_t spscring_p_alloc(struct spscring *ring, size_t *psize)
Allocates a consecutive range of indices, including wrapping, in a single-producer,...
Definition: spscring.c:98
This is the internal header file of the I/O library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
void aligned_free(void *ptr)
Causes the space at ptr to be deallocated, that is, made available for further allocation.
Definition: stdlib.c:90
void * aligned_alloc(size_t alignment, size_t size)
Allocates space for an object whose alignment is specified by alignment, whose size is specified by s...
Definition: stdlib.c:46
A CAN network interface.
Definition: net.c:37
A CAN error frame.
Definition: err.h:28
int state
The state of the CAN node (one of CAN_STATE_ACTIVE, CAN_STATE_PASSIVE or CAN_STATE_BUSOFF).
Definition: err.h:33
int error
The error flags of the CAN bus (any combination of CAN_ERROR_BIT, CAN_ERROR_STUFF,...
Definition: err.h:39
A CAN or CAN FD format frame.
Definition: msg.h:87
An executable task.
Definition: task.h:41
int result
The result of the read operation: 1 if a CAN frame is received, 0 if an error frame is received,...
Definition: can.h:68
int errc
The error number, obtained as if by get_errc(), if result is -1.
Definition: can.h:70
A CAN channel read operation.
Definition: can.h:74
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the read operation.
Definition: can.h:98
struct io_can_chan_read_result r
The result of the read operation.
Definition: can.h:100
A CAN channel write operation.
Definition: can.h:110
const struct can_msg * msg
A pointer to the CAN frame to be written.
Definition: can.h:116
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the write operation.
Definition: can.h:121
int errc
The error number, obtained as if by get_errc(), if an error occurred or the operation was canceled.
Definition: can.h:126
The implementation of a CAN network interface.
Definition: can_net.c:65
struct can_msg write_msg
The CAN frame being written.
Definition: can_net.c:100
void * on_can_error_arg
The user-specified argument for #on_error_func.
Definition: can_net.c:157
struct io_svc svc
The I/O service representing the channel.
Definition: can_net.c:67
mtx_t mtx
The mutex protecting the callbacks, flags and internal CAN network interface.
Definition: can_net.c:118
int read_errc
The error code of the last read operation.
Definition: can_net.c:94
unsigned started
A flag indicating wheter the CAN network interface has been started.
Definition: can_net.c:159
struct can_msg * tx_buf
The transmit queue.
Definition: can_net.c:110
int txtimeo
The timeout (in milliseconds) when waiting for a CAN frame write confirmation.
Definition: can_net.c:84
struct can_msg read_msg
The CAN frame being read.
Definition: can_net.c:88
void * on_queue_error_arg
The user-specified argument for on_queue_error_func.
Definition: can_net.c:135
unsigned shutdown
A flag indicating whether the I/O service has been shut down.
Definition: can_net.c:161
void * on_can_state_arg
The user-specified argument for #on_state_func.
Definition: can_net.c:150
io_can_net_on_can_state_func_t * on_can_state_func
A pointer to the function to be invoked when a CAN bus state change is detected.
Definition: can_net.c:148
void * on_read_error_arg
The user-specified argument for on_read_error_func.
Definition: can_net.c:127
unsigned read_submitted
A flag indicating whether read has been submitted to chan.
Definition: can_net.c:167
io_can_net_on_error_func_t * on_write_error_func
A pointer to the function invoked when a new CAN frame write error occurs, or when a write operation ...
Definition: can_net.c:141
int write_errc
The error code of the last write operation.
Definition: can_net.c:104
int state
The current state of the CAN bus.
Definition: can_net.c:98
struct io_can_chan_write write
The operation used to write CAN frames.
Definition: can_net.c:102
size_t tx_errcnt
The number of frames dropped due to the transmit queue being full.
Definition: can_net.c:112
size_t write_errcnt
The number of errors since the last successful write operation.
Definition: can_net.c:106
io_timer_t * timer
A pointer to the timer used for CAN network events.
Definition: can_net.c:73
io_can_net_on_error_func_t * on_queue_error_func
A pointer to the function invoked when a CAN frame is dropped because the transmit queue is full,...
Definition: can_net.c:133
struct io_tqueue_wait wait_next
The operation used to wait for the next CANopen event.
Definition: can_net.c:77
io_can_chan_t * chan
A pointer to a CAN channel.
Definition: can_net.c:86
unsigned wait_next_submitted
A flag indicating whether wait_next has been submitted to tq.
Definition: can_net.c:163
io_ctx_t * ctx
A pointer to the I/O context with which the channel is registered.
Definition: can_net.c:69
io_tqueue_t * tq
A pointer to the timer queue used to schedule wait operations.
Definition: can_net.c:75
struct spscring tx_ring
The ring buffer used to control the transmit queue.
Definition: can_net.c:108
struct io_tqueue_wait wait_confirm
The operation used to wait for a CAN frame write confirmation.
Definition: can_net.c:79
can_net_t * net
A pointer to the internal CAN network interface.
Definition: can_net.c:171
size_t read_errcnt
The number of errors since the last successful read operation.
Definition: can_net.c:96
unsigned write_submitted
A flag indicating whether write has been submitted to chan.
Definition: can_net.c:169
io_can_net_on_can_error_func_t * on_can_error_func
A pointer to the function to be invoked when an error is detected on the CAN bus.
Definition: can_net.c:155
io_can_net_on_error_func_t * on_read_error_func
A pointer to the function invoked when a new CAN frame read error occurs, or when a read operation co...
Definition: can_net.c:125
struct io_can_chan_read read
The operation used to read CAN frames.
Definition: can_net.c:92
void * on_write_error_arg
The user-specified argument for on_write_error_func.
Definition: can_net.c:143
unsigned wait_confirm_submitted
A flag indicating whether wait_confirm has been submitted to tq.
Definition: can_net.c:165
struct timespec next
The time at which the next CAN timer will trigger.
Definition: can_net.c:173
ev_exec_t * exec
A pointer to the executor ...
Definition: can_net.c:71
struct can_err read_err
The CAN error frame being read.
Definition: can_net.c:90
Definition: ctx.c:35
The virtual table of an I/O service.
Definition: ctx.h:67
An I/O service.
Definition: ctx.h:49
A wait operation suitable for use with a timer queue.
Definition: tqueue.h:36
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the wait operation.
Definition: tqueue.h:43
struct timespec value
The absolute expiration time.
Definition: tqueue.h:38
A single-producer, single-consumer ring buffer.
Definition: spscring.h:61
This header file is part of the C11 and POSIX compatibility library; it includes <threads....
int mtx_init(mtx_t *mtx, int type)
Creates a mutex object with properties indicated by type, which must have one of the four values:
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
void thrd_yield(void)
Endeavors to permit other threads to run, even if the current thread would ordinarily continue to run...
@ thrd_success
Indicates that the requested operation succeeded.
Definition: threads.h:121
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
pthread_mutex_t mtx_t
A complete object type that holds an identifier for a mutex.
Definition: threads.h:102
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
@ mtx_plain
A mutex type that supports neither timeout nor test and return.
Definition: threads.h:109
io_timer_t * io_tqueue_get_timer(const io_tqueue_t *tq)
Returns a pointer to the I/O timer used by the timer queue.
Definition: tqueue.c:223
void io_tqueue_destroy(io_tqueue_t *tq)
Destroys a timer queue.
Definition: tqueue.c:206
size_t io_tqueue_abort_wait(io_tqueue_t *tq, struct io_tqueue_wait *wait)
Aborts the specified timer queue wait operation if it is pending.
Definition: tqueue.c:307
struct io_tqueue_wait * io_tqueue_wait_from_task(struct ev_task *task)
Obtains a pointer to a timer queue wait operation from a pointer to its completion task.
Definition: tqueue.c:351
void io_tqueue_submit_wait(io_tqueue_t *tq, struct io_tqueue_wait *wait)
Submits a wait operation to a timer queue.
Definition: tqueue.c:231
#define IO_TQUEUE_WAIT_INIT(sec, nsec, exec, func)
The static initializer for io_tqueue_wait.
Definition: tqueue.h:53
io_tqueue_t * io_tqueue_create(io_timer_t *timer, ev_exec_t *exec)
Creates a new timer queue.
Definition: tqueue.c:179
This header file is part of the utilities library; it contains the time function declarations.
int timespec_cmp(const void *p1, const void *p2)
Compares two times.
Definition: time.h:228
void timespec_add_msec(struct timespec *tp, uint_least64_t msec)
Adds msec milliseconds to the time at tp.
Definition: time.h:135