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