Lely core libraries  2.3.4
vcan.c
Go to the documentation of this file.
1 
24 #include "can.h"
25 
26 #if !LELY_NO_MALLOC
27 
28 #if !LELY_NO_THREADS
29 #include <lely/libc/threads.h>
30 #endif
31 #include <lely/io2/ctx.h>
32 #include <lely/io2/vcan.h>
33 #include <lely/util/diag.h>
34 #include <lely/util/spscring.h>
35 #include <lely/util/time.h>
36 #include <lely/util/util.h>
37 
38 #include <assert.h>
39 #include <stdint.h>
40 #include <stdlib.h>
41 
42 #ifndef LELY_IO_VCAN_BITRATE
43 #define LELY_IO_VCAN_BITRATE 1000000
45 #endif
46 
47 #ifndef LELY_IO_VCAN_RXLEN
48 
52 #define LELY_IO_VCAN_RXLEN 1024
53 #endif
54 
55 struct io_vcan_frame {
56  int is_err;
57  union {
58  struct can_msg msg;
59  struct can_err err;
60  } u;
61  struct timespec ts;
62 };
63 
64 static int io_vcan_ctrl_stop(io_can_ctrl_t *ctrl);
65 static int io_vcan_ctrl_stopped(const io_can_ctrl_t *ctrl);
66 static int io_vcan_ctrl_restart(io_can_ctrl_t *ctrl);
67 static int io_vcan_ctrl_get_bitrate(
68  const io_can_ctrl_t *ctrl, int *pnominal, int *pdata);
69 static int io_vcan_ctrl_set_bitrate(io_can_ctrl_t *ctrl, int nominal, int data);
70 static int io_vcan_ctrl_get_state(const io_can_ctrl_t *ctrl);
71 
72 // clang-format off
73 static const struct io_can_ctrl_vtbl io_vcan_ctrl_vtbl = {
74  &io_vcan_ctrl_stop,
75  &io_vcan_ctrl_stopped,
76  &io_vcan_ctrl_restart,
77  &io_vcan_ctrl_get_bitrate,
78  &io_vcan_ctrl_set_bitrate,
79  &io_vcan_ctrl_get_state
80 };
81 // clang-format on
82 
84 struct io_vcan_ctrl {
86  const struct io_can_ctrl_vtbl *ctrl_vptr;
93  int flags;
94 #if !LELY_NO_THREADS
95 
105 #endif
106  int stopped;
109  int nominal;
111  int data;
113  int state;
115  struct sllist list;
116 };
117 
118 static inline struct io_vcan_ctrl *io_vcan_ctrl_from_ctrl(
119  const io_can_ctrl_t *ctrl);
120 
121 static void io_vcan_ctrl_insert(io_can_ctrl_t *ctrl, io_can_chan_t *chan);
122 static void io_vcan_ctrl_remove(io_can_ctrl_t *ctrl, io_can_chan_t *chan);
123 
124 static void io_vcan_ctrl_signal(struct spscring *ring, void *arg);
125 
126 static int io_vcan_ctrl_write(io_can_ctrl_t *ctrl, io_can_chan_t *chan,
127  const struct can_msg *msg, const struct can_err *err,
128  int timeout);
129 
130 static void io_vcan_ctrl_do_stop(struct io_vcan_ctrl *vcan_ctrl);
131 
132 static io_ctx_t *io_vcan_chan_dev_get_ctx(const io_dev_t *dev);
133 static ev_exec_t *io_vcan_chan_dev_get_exec(const io_dev_t *dev);
134 static size_t io_vcan_chan_dev_cancel(io_dev_t *dev, struct ev_task *task);
135 static size_t io_vcan_chan_dev_abort(io_dev_t *dev, struct ev_task *task);
136 
137 // clang-format off
138 static const struct io_dev_vtbl io_vcan_chan_dev_vtbl = {
139  &io_vcan_chan_dev_get_ctx,
140  &io_vcan_chan_dev_get_exec,
141  &io_vcan_chan_dev_cancel,
142  &io_vcan_chan_dev_abort
143 };
144 // clang-format on
145 
146 static io_dev_t *io_vcan_chan_get_dev(const io_can_chan_t *chan);
147 static int io_vcan_chan_get_flags(const io_can_chan_t *chan);
148 static int io_vcan_chan_read(io_can_chan_t *chan, struct can_msg *msg,
149  struct can_err *err, struct timespec *tp, int timeout);
150 static void io_vcan_chan_submit_read(
151  io_can_chan_t *chan, struct io_can_chan_read *read);
152 static int io_vcan_chan_write(
153  io_can_chan_t *chan, const struct can_msg *msg, int timeout);
154 static void io_vcan_chan_submit_write(
155  io_can_chan_t *chan, struct io_can_chan_write *write);
156 
157 // clang-format off
158 static const struct io_can_chan_vtbl io_vcan_chan_vtbl = {
159  &io_vcan_chan_get_dev,
160  &io_vcan_chan_get_flags,
161  &io_vcan_chan_read,
162  &io_vcan_chan_submit_read,
163  &io_vcan_chan_write,
164  &io_vcan_chan_submit_write
165 };
166 // clang-format on
167 
168 static void io_vcan_chan_svc_shutdown(struct io_svc *svc);
169 
170 // clang-format off
171 static const struct io_svc_vtbl io_vcan_chan_svc_vtbl = {
172  NULL,
173  &io_vcan_chan_svc_shutdown
174 };
175 // clang-format on
176 
178 struct io_vcan_chan {
180  const struct io_dev_vtbl *dev_vptr;
184  struct io_svc svc;
194  struct spscring rxring;
197 #if !LELY_NO_THREADS
198 
208 #endif
209 
218  struct slnode node;
220  unsigned shutdown : 1;
222  unsigned stopped : 1;
224  unsigned read_posted : 1;
226  unsigned write_posted : 1;
233 };
234 
235 static void io_vcan_chan_read_task_func(struct ev_task *task);
236 static void io_vcan_chan_write_task_func(struct ev_task *task);
237 
238 static inline struct io_vcan_chan *io_vcan_chan_from_dev(const io_dev_t *dev);
239 static inline struct io_vcan_chan *io_vcan_chan_from_chan(
240  const io_can_chan_t *chan);
241 static inline struct io_vcan_chan *io_vcan_chan_from_svc(
242  const struct io_svc *svc);
243 
244 static void io_vcan_chan_signal(struct spscring *ring, void *arg);
245 
246 static void io_vcan_chan_do_pop(struct io_vcan_chan *vcan,
247  struct sllist *read_queue, struct sllist *write_queue,
248  struct ev_task *task);
249 
250 static size_t io_vcan_chan_do_abort_tasks(struct io_vcan_chan *vcan);
251 
252 void *
253 io_vcan_ctrl_alloc(void)
254 {
255  struct io_vcan_ctrl *vcan = malloc(sizeof(*vcan));
256  if (!vcan) {
257 #if !LELY_NO_ERRNO
258  set_errc(errno2c(errno));
259 #endif
260  return NULL;
261  }
262  // Suppress a GCC maybe-uninitialized warning.
263  vcan->ctrl_vptr = NULL;
264  // cppcheck-suppress memleak symbolName=vcan
265  return &vcan->ctrl_vptr;
266 }
267 
268 void
269 io_vcan_ctrl_free(void *ptr)
270 {
271  if (ptr)
272  free(io_vcan_ctrl_from_ctrl(ptr));
273 }
274 
276 io_vcan_ctrl_init(io_can_ctrl_t *ctrl, io_clock_t *clock, int flags,
277  int nominal, int data, int state)
278 {
279  struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
280  assert(clock);
281 
282  if (!nominal)
284 #if !LELY_NO_CANFD
285  if (!data)
286  data = nominal;
287 #else
288  (void)data;
289 #endif
290 
291 #if !LELY_NO_THREADS
292  int errc = 0;
293 #endif
294 
295  vcan->ctrl_vptr = &io_vcan_ctrl_vtbl;
296 
297  vcan->clock = clock;
298 
299  vcan->flags = flags;
300 
301 #if !LELY_NO_THREADS
302  if (mtx_init(&vcan->mtx, mtx_plain) != thrd_success) {
303  errc = get_errc();
304  goto error_init_mtx;
305  }
306 
307  if (cnd_init(&vcan->cond) != thrd_success) {
308  errc = get_errc();
309  goto error_init_cond;
310  }
311 #endif
312 
313  vcan->stopped = state == CAN_STATE_STOPPED;
314  vcan->nominal = nominal;
315  vcan->data = 0;
316 #if !LELY_NO_CANFD
317  if (vcan->flags & IO_CAN_BUS_FLAG_BRS)
318  vcan->data = data;
319 #endif
320  vcan->state = state;
321 
322  sllist_init(&vcan->list);
323 
324  return ctrl;
325 
326 #if !LELY_NO_THREADS
327  // cnd_destroy(&vcan->cond);
328 error_init_cond:
329  mtx_destroy(&vcan->mtx);
330 error_init_mtx:
331  set_errc(errc);
332  return NULL;
333 #endif
334 }
335 
336 void
337 io_vcan_ctrl_fini(io_can_ctrl_t *ctrl)
338 {
339  struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
340 
341  assert(sllist_empty(&vcan->list));
342 
343 #if LELY_NO_THREADS
344  (void)vcan;
345 #else
346  cnd_destroy(&vcan->cond);
347  mtx_destroy(&vcan->mtx);
348 #endif
349 }
350 
353  io_clock_t *clock, int flags, int nominal, int data, int state)
354 {
355  int errc = 0;
356 
357  io_can_ctrl_t *ctrl = io_vcan_ctrl_alloc();
358  if (!ctrl) {
359  errc = get_errc();
360  goto error_alloc;
361  }
362 
363  io_can_ctrl_t *tmp = io_vcan_ctrl_init(
364  ctrl, clock, flags, nominal, data, state);
365  if (!tmp) {
366  errc = get_errc();
367  goto error_init;
368  }
369  ctrl = tmp;
370 
371  return ctrl;
372 
373 error_init:
374  io_vcan_ctrl_free((void *)ctrl);
375 error_alloc:
376  set_errc(errc);
377  return NULL;
378 }
379 
380 void
382 {
383  if (ctrl) {
384  io_vcan_ctrl_fini(ctrl);
385  io_vcan_ctrl_free((void *)ctrl);
386  }
387 }
388 
389 void
391 {
392  struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
393 
394 #if !LELY_NO_THREADS
395  mtx_lock(&vcan->mtx);
396 #endif
397  int changed = vcan->state != state;
398  if (changed) {
399  vcan->state = state;
400  if (!vcan->stopped && vcan->state == CAN_STATE_STOPPED)
401  io_vcan_ctrl_do_stop(vcan);
402  }
403 #if !LELY_NO_THREADS
404  mtx_unlock(&vcan->mtx);
405 #endif
406 
407  // Send an error frame if the state of the CAN bus changed. We ignore
408  // write errors, since the user does not expect this operation to block.
409  if (changed && state != CAN_STATE_STOPPED
410  && (vcan->flags & IO_CAN_BUS_FLAG_ERR)) {
411  struct can_err err = { .state = state };
412  int errsv = get_errc();
413  if (io_vcan_ctrl_write_err(ctrl, &err, 0) == -1)
414  set_errc(errsv);
415  }
416 }
417 
418 int
420  io_can_ctrl_t *ctrl, const struct can_msg *msg, int timeout)
421 {
422  return io_vcan_ctrl_write(ctrl, NULL, msg, NULL, timeout);
423 }
424 
425 int
427  io_can_ctrl_t *ctrl, const struct can_err *err, int timeout)
428 {
429  return io_vcan_ctrl_write(ctrl, NULL, NULL, err, timeout);
430 }
431 
432 void *
433 io_vcan_chan_alloc(void)
434 {
435  struct io_vcan_chan *vcan = malloc(sizeof(*vcan));
436  if (!vcan) {
437 #if !LELY_NO_ERRNO
438  set_errc(errno2c(errno));
439 #endif
440  return NULL;
441  }
442  // Suppress a GCC maybe-uninitialized warning.
443  vcan->chan_vptr = NULL;
444  // cppcheck-suppress memleak symbolName=vcan
445  return &vcan->chan_vptr;
446 }
447 
448 void
449 io_vcan_chan_free(void *ptr)
450 {
451  if (ptr)
452  free(io_vcan_chan_from_chan(ptr));
453 }
454 
456 io_vcan_chan_init(io_can_chan_t *chan, io_ctx_t *ctx, ev_exec_t *exec,
457  size_t rxlen)
458 {
459  struct io_vcan_chan *vcan = io_vcan_chan_from_chan(chan);
460  assert(ctx);
461  assert(exec);
462 
463  if (!rxlen)
464  rxlen = LELY_IO_VCAN_RXLEN;
465 
466  int errc = 0;
467 
468  vcan->dev_vptr = &io_vcan_chan_dev_vtbl;
469  vcan->chan_vptr = &io_vcan_chan_vtbl;
470 
471  vcan->svc = (struct io_svc)IO_SVC_INIT(&io_vcan_chan_svc_vtbl);
472  vcan->ctx = ctx;
473 
474  vcan->exec = exec;
475 
476  vcan->read_task = (struct ev_task)EV_TASK_INIT(
477  vcan->exec, &io_vcan_chan_read_task_func);
478  vcan->write_task = (struct ev_task)EV_TASK_INIT(
479  vcan->exec, &io_vcan_chan_write_task_func);
480 
481  spscring_init(&vcan->rxring, rxlen);
482  vcan->rxbuf = calloc(rxlen, sizeof(struct io_vcan_frame));
483  if (!vcan->rxbuf) {
484 #if !LELY_NO_ERRNO
485  errc = errno2c(errno);
486 #endif
487  goto error_alloc_rxbuf;
488  }
489 
490 #if !LELY_NO_THREADS
491  if (mtx_init(&vcan->mtx, mtx_plain) != thrd_success) {
492  errc = get_errc();
493  goto error_init_mtx;
494  }
495 
496  if (cnd_init(&vcan->cond) != thrd_success) {
497  errc = get_errc();
498  goto error_init_cond;
499  }
500 #endif
501 
502  vcan->ctrl = NULL;
503  slnode_init(&vcan->node);
504 
505  vcan->shutdown = 0;
506  vcan->stopped = 0;
507  vcan->read_posted = 0;
508  vcan->write_posted = 0;
509 
510  sllist_init(&vcan->read_queue);
511  sllist_init(&vcan->write_queue);
512  vcan->current_write = NULL;
513 
514  io_ctx_insert(vcan->ctx, &vcan->svc);
515 
516  return chan;
517 
518 #if !LELY_NO_THREADS
519  // cnd_destroy(&vcan->cond);
520 error_init_cond:
521  mtx_destroy(&vcan->mtx);
522 error_init_mtx:
523 #endif
524  free(vcan->rxbuf);
525 error_alloc_rxbuf:
526  set_errc(errc);
527  return NULL;
528 }
529 
530 void
531 io_vcan_chan_fini(io_can_chan_t *chan)
532 {
533  struct io_vcan_chan *vcan = io_vcan_chan_from_chan(chan);
534 
535  // Close the CAN channel.
536  io_vcan_chan_close(chan);
537 
538  io_ctx_remove(vcan->ctx, &vcan->svc);
539  // Cancel all pending tasks.
540  io_vcan_chan_svc_shutdown(&vcan->svc);
541 
542  // Abort any consumer wait operation. Any producer wait operation was
543  // canceled when the channel was closed.
545 
546 #if !LELY_NO_THREADS
547  int warning = 0;
548  mtx_lock(&vcan->mtx);
549  // If necessary, busy-wait until io_vcan_chan_read_task_func() and
550  // io_vcan_chan_write_task_func() complete.
551  while (vcan->read_posted || vcan->write_posted) {
552  if (io_vcan_chan_do_abort_tasks(vcan))
553  continue;
554  mtx_unlock(&vcan->mtx);
555  if (!warning) {
556  warning = 1;
557  diag(DIAG_WARNING, 0,
558  "io_vcan_chan_fini() invoked with pending operations");
559  }
560  thrd_yield();
561  mtx_lock(&vcan->mtx);
562  }
563  mtx_unlock(&vcan->mtx);
564 
565  cnd_destroy(&vcan->cond);
566  mtx_destroy(&vcan->mtx);
567 #endif
568 
569  free(vcan->rxbuf);
570 }
571 
574 {
575  int errc = 0;
576 
577  io_can_chan_t *chan = io_vcan_chan_alloc();
578  if (!chan) {
579  errc = get_errc();
580  goto error_alloc;
581  }
582 
583  io_can_chan_t *tmp = io_vcan_chan_init(chan, ctx, exec, rxlen);
584  if (!tmp) {
585  errc = get_errc();
586  goto error_init;
587  }
588  chan = tmp;
589 
590  return chan;
591 
592 error_init:
593  io_vcan_chan_free((void *)chan);
594 error_alloc:
595  set_errc(errc);
596  return NULL;
597 }
598 
599 void
601 {
602  if (chan) {
603  io_vcan_chan_fini(chan);
604  io_vcan_chan_free((void *)chan);
605  }
606 }
607 
610 {
611  const struct io_vcan_chan *vcan = io_vcan_chan_from_chan(chan);
612 
613 #if !LELY_NO_THREADS
614  mtx_lock((mtx_t *)&vcan->mtx);
615 #endif
616  io_can_ctrl_t *ctrl = vcan->ctrl;
617 #if !LELY_NO_THREADS
618  mtx_unlock((mtx_t *)&vcan->mtx);
619 #endif
620 
621  return ctrl;
622 }
623 
624 void
626 {
627  io_vcan_chan_close(chan);
628  if (ctrl)
629  io_vcan_ctrl_insert(ctrl, chan);
630 }
631 
632 int
634 {
635  return io_vcan_chan_get_ctrl(chan) != NULL;
636 }
637 
638 void
640 {
642  if (ctrl)
643  io_vcan_ctrl_remove(ctrl, chan);
644 }
645 
646 static int
647 io_vcan_ctrl_stop(io_can_ctrl_t *ctrl)
648 {
649  struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
650 
651 #if !LELY_NO_THREADS
652  mtx_lock(&vcan->mtx);
653 #endif
654  io_vcan_ctrl_do_stop(vcan);
655 #if !LELY_NO_THREADS
656  mtx_unlock(&vcan->mtx);
657 #endif
658 
659  return 0;
660 }
661 
662 static int
663 io_vcan_ctrl_stopped(const io_can_ctrl_t *ctrl)
664 {
665  const struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
666 
667 #if !LELY_NO_THREADS
668  mtx_lock((mtx_t *)&vcan->mtx);
669 #endif
670  int stopped = vcan->stopped;
671 #if !LELY_NO_THREADS
672  mtx_unlock((mtx_t *)&vcan->mtx);
673 #endif
674 
675  return stopped;
676 }
677 
678 static int
679 io_vcan_ctrl_restart(io_can_ctrl_t *ctrl)
680 {
681  struct io_vcan_ctrl *vcan_ctrl = io_vcan_ctrl_from_ctrl(ctrl);
682 
683 #if !LELY_NO_THREADS
684  mtx_lock(&vcan_ctrl->mtx);
685 #endif
686  int stopped = vcan_ctrl->stopped;
687  if (stopped) {
688  vcan_ctrl->stopped = 0;
689  vcan_ctrl->state = CAN_STATE_ACTIVE;
690  // Update the state of each channel.
691  sllist_foreach (&vcan_ctrl->list, node) {
692  struct io_vcan_chan *vcan_chan = structof(
693  node, struct io_vcan_chan, node);
694 #if !LELY_NO_THREADS
695  mtx_lock(&vcan_chan->mtx);
696 #endif
697  vcan_chan->stopped = 0;
698 #if !LELY_NO_THREADS
699  mtx_unlock(&vcan_chan->mtx);
700 #endif
701  }
702  }
703 #if !LELY_NO_THREADS
704  mtx_unlock(&vcan_ctrl->mtx);
705 #endif
706 
707  // Send an error frame if the CAN bus was restarted. We ignore write
708  // errors, since the user does not expect this operation to block.
709  if (stopped && (vcan_ctrl->flags & IO_CAN_BUS_FLAG_ERR)) {
710  struct can_err err = { .state = CAN_STATE_ACTIVE };
711  int errsv = get_errc();
712  if (io_vcan_ctrl_write_err(ctrl, &err, 0) == -1)
713  set_errc(errsv);
714  }
715 
716  return 0;
717 }
718 
719 static int
720 io_vcan_ctrl_get_bitrate(const io_can_ctrl_t *ctrl, int *pnominal, int *pdata)
721 {
722  const struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
723 
724 #if !LELY_NO_THREADS
725  mtx_lock((mtx_t *)&vcan->mtx);
726 #endif
727  if (pnominal)
728  *pnominal = vcan->nominal;
729  if (pdata)
730  *pdata = vcan->data;
731 #if !LELY_NO_THREADS
732  mtx_unlock((mtx_t *)&vcan->mtx);
733 #endif
734 
735  return 0;
736 }
737 
738 static int
739 io_vcan_ctrl_set_bitrate(io_can_ctrl_t *ctrl, int nominal, int data)
740 {
741  struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
742 
743 #if !LELY_NO_THREADS
744  mtx_lock(&vcan->mtx);
745 #endif
746  io_vcan_ctrl_do_stop(vcan);
747  vcan->nominal = nominal;
748 #if !LELY_NO_CANFD
749  if (vcan->flags & IO_CAN_BUS_FLAG_BRS)
750  vcan->data = data;
751 #else
752  (void)data;
753 #endif
754 #if !LELY_NO_THREADS
755  mtx_unlock(&vcan->mtx);
756 #endif
757 
758  return 0;
759 }
760 
761 static int
762 io_vcan_ctrl_get_state(const io_can_ctrl_t *ctrl)
763 {
764  const struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
765 
766 #if !LELY_NO_THREADS
767  mtx_lock((mtx_t *)&vcan->mtx);
768 #endif
769  int state = vcan->state;
770 #if !LELY_NO_THREADS
771  mtx_unlock((mtx_t *)&vcan->mtx);
772 #endif
773 
774  return state;
775 }
776 
777 static inline struct io_vcan_ctrl *
778 io_vcan_ctrl_from_ctrl(const io_can_ctrl_t *ctrl)
779 {
780  assert(ctrl);
781 
782  return structof(ctrl, struct io_vcan_ctrl, ctrl_vptr);
783 }
784 
785 static void
786 io_vcan_ctrl_insert(io_can_ctrl_t *ctrl, io_can_chan_t *chan)
787 {
788  struct io_vcan_ctrl *vcan_ctrl = io_vcan_ctrl_from_ctrl(ctrl);
789  struct io_vcan_chan *vcan_chan = io_vcan_chan_from_chan(chan);
790 
791 #if !LELY_NO_THREADS
792  mtx_lock(&vcan_ctrl->mtx);
793 #endif
794  sllist_push_back(&vcan_ctrl->list, &vcan_chan->node);
795 #if !LELY_NO_THREADS
796  mtx_lock(&vcan_chan->mtx);
797 #endif
798  vcan_chan->ctrl = ctrl;
799  vcan_chan->stopped = vcan_ctrl->stopped;
800 #if !LELY_NO_THREADS
801  mtx_unlock(&vcan_chan->mtx);
802 #endif
803 #if !LELY_NO_THREADS
804  mtx_unlock(&vcan_ctrl->mtx);
805 #endif
806 }
807 
808 static void
809 io_vcan_ctrl_remove(io_can_ctrl_t *ctrl, io_can_chan_t *chan)
810 {
811  struct io_vcan_ctrl *vcan_ctrl = io_vcan_ctrl_from_ctrl(ctrl);
812  struct io_vcan_chan *vcan_chan = io_vcan_chan_from_chan(chan);
813 
814  struct sllist read_queue, write_queue;
815  sllist_init(&read_queue);
816  sllist_init(&write_queue);
817 
818 #if !LELY_NO_THREADS
819  mtx_lock(&vcan_ctrl->mtx);
820 #endif
821  if (sllist_remove(&vcan_ctrl->list, &vcan_chan->node)) {
822  // Abort any wait operation started by io_vcan_ctrl_write().
823  spscring_p_abort_wait(&vcan_chan->rxring);
824 #if !LELY_NO_THREADS
825  mtx_lock(&vcan_chan->mtx);
826 #endif
827  vcan_chan->ctrl = NULL;
828  // Cancel all pending operations.
829  sllist_append(&read_queue, &vcan_chan->read_queue);
830  sllist_append(&write_queue, &vcan_chan->write_queue);
831  vcan_chan->current_write = NULL;
832 #if !LELY_NO_THREADS
833  mtx_unlock(&vcan_chan->mtx);
834 #endif
835  }
836 #if !LELY_NO_THREADS
837  mtx_unlock(&vcan_ctrl->mtx);
838 #endif
839 
840  io_can_chan_read_queue_post(&read_queue, -1, errnum2c(ERRNUM_CANCELED));
841  io_can_chan_write_queue_post(&write_queue, errnum2c(ERRNUM_CANCELED));
842 }
843 
844 static void
845 io_vcan_ctrl_signal(struct spscring *ring, void *arg)
846 {
847  (void)ring;
848  struct io_vcan_ctrl *vcan = arg;
849  assert(vcan);
850 
851 #if !LELY_NO_THREADS
852  mtx_lock(&vcan->mtx);
853 #endif
854  // Post the write tasks of all channels, if necessary, to process any
855  // pending write operations.
856  sllist_foreach (&vcan->list, node) {
857  struct io_vcan_chan *chan =
858  structof(node, struct io_vcan_chan, node);
859 #if !LELY_NO_THREADS
860  mtx_lock(&chan->mtx);
861 #endif
862  if (!chan->write_posted && !sllist_empty(&chan->write_queue)) {
863  chan->write_posted = 1;
864  ev_exec_post(chan->write_task.exec, &chan->write_task);
865  }
866 #if !LELY_NO_THREADS
867  mtx_unlock(&chan->mtx);
868 #endif
869  }
870 #if !LELY_NO_THREADS
871  // Wake up all threads waiting for this signal.
872  cnd_broadcast(&vcan->cond);
873  mtx_unlock(&vcan->mtx);
874 #endif
875 }
876 
877 static int
878 io_vcan_ctrl_write(io_can_ctrl_t *ctrl, io_can_chan_t *chan,
879  const struct can_msg *msg, const struct can_err *err,
880  int timeout)
881 {
882  struct io_vcan_ctrl *vcan_ctrl = io_vcan_ctrl_from_ctrl(ctrl);
883  assert(!msg || !err);
884 
885  if (!msg && !err)
886  return 0;
887 
888  struct timespec ts = { 0, 0 };
889  // Compute the absolute timeout for cnd_timedwait().
890 #if !LELY_NO_THREADS
891  if (timeout > 0) {
892 #if LELY_NO_TIMEOUT
893  timeout = 0;
894 #else
895  if (!timespec_get(&ts, TIME_UTC))
896  return -1;
897  timespec_add_msec(&ts, timeout);
898 #endif
899  }
900 #endif
901 
902 #if !LELY_NO_CANFD
903  // Check if CAN FD frames are supported.
904  if (msg) {
905  int flags = 0;
906  if (msg->flags & CAN_FLAG_FDF)
907  flags |= IO_CAN_BUS_FLAG_FDF;
908  if (msg->flags & CAN_FLAG_BRS)
909  flags |= IO_CAN_BUS_FLAG_BRS;
910  if ((flags & vcan_ctrl->flags) != flags) {
912  return -1;
913  }
914  }
915 #endif
916  // Check if error frames are supported.
917  if (err && !(vcan_ctrl->flags & IO_CAN_BUS_FLAG_ERR)) {
919  return -1;
920  }
921 
922 #if !LELY_NO_THREADS
923  mtx_lock(&vcan_ctrl->mtx);
924 #endif
925 
926  // Return the same error as SocketCAN when the controller is stopped.
927  if (vcan_ctrl->stopped) {
928 #if !LELY_NO_THREADS
929  mtx_unlock(&vcan_ctrl->mtx);
930 #endif
932  return -1;
933  }
934 
935  // Check if all registered channels have a slot available in their
936  // receive queue.
937  for (;;) {
938  struct io_vcan_chan *vcan_chan = NULL;
939  int wouldblock = 0;
940  sllist_foreach (&vcan_ctrl->list, node) {
941  vcan_chan = structof(node, struct io_vcan_chan, node);
942  // Skip the sending channel.
943  if (chan && chan == &vcan_chan->chan_vptr)
944  continue;
945  // Try to allocate a single slot.
946  size_t n = 1;
947  spscring_p_alloc(&vcan_chan->rxring, &n);
948  if (!n) {
949  wouldblock = 1;
950  break;
951  }
952  }
953  // If all channels are ready, continue below with writing the
954  // frame.
955  if (!wouldblock)
956  break;
957  // Always submit a wait operation, even when timeout is 0, so
958  // pending write operations will be signaled once the blocked
959  // channel becomes ready.
960  // clang-format off
961  if (!spscring_p_submit_wait(&vcan_chan->rxring, 1,
962  &io_vcan_ctrl_signal, vcan_ctrl))
963  // clang-format on
964  // If the wait condition was already sastisfied, try
965  // again.
966  continue;
967  // Wait for the blocked channel to signal it is ready, or time
968  // out if that takes too long.
969  if (!timeout) {
970 #if !LELY_NO_THREADS
971  mtx_unlock(&vcan_ctrl->mtx);
972 #endif
974  return -1;
975  }
976 #if !LELY_NO_THREADS
977  int result;
978 #if !LELY_NO_TIMEOUT
979  if (timeout > 0)
980  result = cnd_timedwait(
981  &vcan_ctrl->cond, &vcan_ctrl->mtx, &ts);
982  else
983 #endif
984  result = cnd_wait(&vcan_ctrl->cond, &vcan_ctrl->mtx);
985  if (result != thrd_success) {
986  mtx_unlock(&vcan_ctrl->mtx);
987 #if !LELY_NO_TIMEOUT
988  if (result == thrd_timedout)
990 #endif
991  return -1;
992  }
993 #endif
994  }
995 
996  // Obtain a timestamp for the CAN frame. We obtain it here, after
997  // waiting above, so the timestamp reflects the actual time the frame
998  // was put on the bus. This guarantees that all frames are ordered in
999  // time.
1000  if (io_clock_gettime(vcan_ctrl->clock, &ts) == -1) {
1001 #if !LELY_NO_THREADS
1002  mtx_unlock(&vcan_ctrl->mtx);
1003 #endif
1004  return -1;
1005  }
1006 
1007  // Put the frame in the receive queue of every channel.
1008  sllist_foreach (&vcan_ctrl->list, node) {
1009  struct io_vcan_chan *vcan_chan =
1010  structof(node, struct io_vcan_chan, node);
1011  // Skip the sending channel.
1012  if (chan && chan == &vcan_chan->chan_vptr)
1013  continue;
1014 
1015  size_t n = 1;
1016  size_t i = spscring_p_alloc(&vcan_chan->rxring, &n);
1017  // We did not release the mutex after checking that all channels
1018  // are ready, so this cannot fail.
1019  assert(n == 1);
1020  if (msg)
1021  vcan_chan->rxbuf[i] = (struct io_vcan_frame){
1022  .is_err = 0, .u.msg = *msg, .ts = ts
1023  };
1024  else
1025  vcan_chan->rxbuf[i] = (struct io_vcan_frame){
1026  .is_err = 1, .u.err = *err, .ts = ts
1027  };
1028  spscring_p_commit(&vcan_chan->rxring, n);
1029  }
1030 
1031 #if !LELY_NO_THREADS
1032  mtx_unlock(&vcan_ctrl->mtx);
1033 #endif
1034 
1035  return 0;
1036 }
1037 
1038 static void
1039 io_vcan_ctrl_do_stop(struct io_vcan_ctrl *vcan_ctrl)
1040 {
1041  assert(vcan_ctrl);
1042 
1043  vcan_ctrl->stopped = 1;
1044  vcan_ctrl->state = CAN_STATE_STOPPED;
1045 
1046  struct sllist read_queue, write_queue;
1047  sllist_init(&read_queue);
1048  sllist_init(&write_queue);
1049 
1050  sllist_foreach (&vcan_ctrl->list, node) {
1051  struct io_vcan_chan *vcan_chan =
1052  structof(node, struct io_vcan_chan, node);
1053 #if !LELY_NO_THREADS
1054  mtx_lock(&vcan_chan->mtx);
1055 #endif
1056  vcan_chan->stopped = 1;
1057  // Cancel all pending operations.
1058  sllist_append(&read_queue, &vcan_chan->read_queue);
1059  sllist_append(&write_queue, &vcan_chan->write_queue);
1060  vcan_chan->current_write = NULL;
1061 #if !LELY_NO_THREADS
1062  mtx_unlock(&vcan_chan->mtx);
1063 #endif
1064  }
1065 
1066  io_can_chan_read_queue_post(&read_queue, -1, errnum2c(ERRNUM_NETDOWN));
1067  io_can_chan_write_queue_post(&write_queue, errnum2c(ERRNUM_NETDOWN));
1068 }
1069 
1070 static io_ctx_t *
1071 io_vcan_chan_dev_get_ctx(const io_dev_t *dev)
1072 {
1073  const struct io_vcan_chan *vcan = io_vcan_chan_from_dev(dev);
1074 
1075  return vcan->ctx;
1076 }
1077 
1078 static ev_exec_t *
1079 io_vcan_chan_dev_get_exec(const io_dev_t *dev)
1080 {
1081  const struct io_vcan_chan *vcan = io_vcan_chan_from_dev(dev);
1082 
1083  return vcan->exec;
1084 }
1085 
1086 static size_t
1087 io_vcan_chan_dev_cancel(io_dev_t *dev, struct ev_task *task)
1088 {
1089  struct io_vcan_chan *vcan = io_vcan_chan_from_dev(dev);
1090 
1091  size_t n = 0;
1092 
1093  struct sllist read_queue, write_queue;
1094  sllist_init(&read_queue);
1095  sllist_init(&write_queue);
1096 
1097 #if !LELY_NO_THREADS
1098  mtx_lock(&vcan->mtx);
1099 #endif
1100  io_vcan_chan_do_pop(vcan, &read_queue, &write_queue, task);
1101  // Mark the ongoing write operation as canceled, if necessary.
1102  if (vcan->current_write && (!task || task == vcan->current_write)) {
1103  vcan->current_write = NULL;
1104  n++;
1105  }
1106 #if !LELY_NO_THREADS
1107  mtx_unlock(&vcan->mtx);
1108 #endif
1109 
1110  size_t nread = io_can_chan_read_queue_post(
1111  &read_queue, -1, errnum2c(ERRNUM_CANCELED));
1112  n = n < SIZE_MAX - nread ? n + nread : SIZE_MAX;
1113  size_t nwrite = io_can_chan_write_queue_post(
1114  &write_queue, errnum2c(ERRNUM_CANCELED));
1115  n = n < SIZE_MAX - nwrite ? n + nwrite : SIZE_MAX;
1116 
1117  return n;
1118 }
1119 
1120 static size_t
1121 io_vcan_chan_dev_abort(io_dev_t *dev, struct ev_task *task)
1122 {
1123  struct io_vcan_chan *vcan = io_vcan_chan_from_dev(dev);
1124 
1125  struct sllist queue;
1126  sllist_init(&queue);
1127 
1128 #if !LELY_NO_THREADS
1129  mtx_lock(&vcan->mtx);
1130 #endif
1131  io_vcan_chan_do_pop(vcan, &queue, &queue, task);
1132 #if !LELY_NO_THREADS
1133  mtx_unlock(&vcan->mtx);
1134 #endif
1135 
1136  return ev_task_queue_abort(&queue);
1137 }
1138 
1139 static io_dev_t *
1140 io_vcan_chan_get_dev(const io_can_chan_t *chan)
1141 {
1142  const struct io_vcan_chan *vcan = io_vcan_chan_from_chan(chan);
1143 
1144  return &vcan->dev_vptr;
1145 }
1146 
1147 static int
1148 io_vcan_chan_get_flags(const io_can_chan_t *chan)
1149 {
1150  const struct io_vcan_chan *vcan_chan = io_vcan_chan_from_chan(chan);
1151  const struct io_vcan_ctrl *vcan_ctrl =
1152  io_vcan_ctrl_from_ctrl(vcan_chan->ctrl);
1153 
1154  return vcan_ctrl->flags;
1155 }
1156 
1157 static int
1158 io_vcan_chan_read(io_can_chan_t *chan, struct can_msg *msg, struct can_err *err,
1159  struct timespec *tp, int timeout)
1160 {
1161  struct io_vcan_chan *vcan = io_vcan_chan_from_chan(chan);
1162 
1163 #if !LELY_NO_THREADS
1164  // Compute the absolute timeout for cnd_timedwait().
1165  struct timespec ts = { 0, 0 };
1166  if (timeout > 0) {
1167 #if LELY_NO_TIMEOUT
1168  timeout = 0;
1169  (void)ts;
1170 #else
1171  if (!timespec_get(&ts, TIME_UTC))
1172  return -1;
1173  timespec_add_msec(&ts, timeout);
1174 #endif
1175  }
1176 #endif
1177 
1178 #if !LELY_NO_THREADS
1179  mtx_lock(&vcan->mtx);
1180 #endif
1181  size_t i = 0;
1182  for (;;) {
1183  // Check if a frame is available in the receive queue.
1184  size_t n = 1;
1185  i = spscring_c_alloc(&vcan->rxring, &n);
1186  if (n)
1187  break;
1188  // Return the same error as SocketCAN when the channel is
1189  // closed.
1190  if (!vcan->ctrl) {
1191 #if !LELY_NO_THREADS
1192  mtx_unlock(&vcan->mtx);
1193 #endif
1195  return -1;
1196  }
1197  // Return the same error as SocketCAN when the controller is
1198  // stopped.
1199  if (vcan->stopped) {
1200 #if !LELY_NO_THREADS
1201  mtx_unlock(&vcan->mtx);
1202 #endif
1204  return -1;
1205  }
1206  // Always submit a wait operation, even when timeout is 0, so
1207  // pending read operations will be signaled once a frame is
1208  // available.
1209  // clang-format off
1210  if (!spscring_c_submit_wait(&vcan->rxring, 1,
1211  &io_vcan_chan_signal, vcan))
1212  // clang-format on
1213  // If the wait condition was already satisfied, try
1214  // again.
1215  continue;
1216  // Wait for the buffer to signal that a frame is available, or
1217  // time out if that takes too long.
1218  if (!timeout) {
1219 #if !LELY_NO_THREADS
1220  mtx_unlock(&vcan->mtx);
1221 #endif
1223  return -1;
1224  }
1225 #if !LELY_NO_THREADS
1226  int result;
1227 #if !LELY_NO_TIMEOUT
1228  if (timeout > 0)
1229  result = cnd_timedwait(&vcan->cond, &vcan->mtx, &ts);
1230  else
1231 #endif
1232  result = cnd_wait(&vcan->cond, &vcan->mtx);
1233  if (result != thrd_success) {
1234  mtx_unlock(&vcan->mtx);
1235 #if !LELY_NO_TIMEOUT
1236  if (result == thrd_timedout)
1238 #endif
1239  return -1;
1240  }
1241 #endif
1242  }
1243  // Copy the frame from the buffer.
1244  struct io_vcan_frame *frame = &vcan->rxbuf[i];
1245  int is_err = frame->is_err;
1246  if (!is_err && msg)
1247  *msg = frame->u.msg;
1248  else if (is_err && err)
1249  *err = frame->u.err;
1250  if (tp)
1251  *tp = frame->ts;
1252  spscring_c_commit(&vcan->rxring, 1);
1253 #if !LELY_NO_THREADS
1254  mtx_unlock(&vcan->mtx);
1255 #endif
1256 
1257  return !is_err;
1258 }
1259 
1260 static void
1261 io_vcan_chan_submit_read(io_can_chan_t *chan, struct io_can_chan_read *read)
1262 {
1263  struct io_vcan_chan *vcan = io_vcan_chan_from_chan(chan);
1264  assert(read);
1265  struct ev_task *task = &read->task;
1266 
1267  if (!task->exec)
1268  task->exec = vcan->exec;
1269  ev_exec_on_task_init(task->exec);
1270 
1271 #if !LELY_NO_THREADS
1272  mtx_lock(&vcan->mtx);
1273 #endif
1274  if (vcan->shutdown) {
1275 #if !LELY_NO_THREADS
1276  mtx_unlock(&vcan->mtx);
1277 #endif
1278  io_can_chan_read_post(read, -1, errnum2c(ERRNUM_CANCELED));
1279  } else if (!vcan->ctrl) {
1280 #if !LELY_NO_THREADS
1281  mtx_unlock(&vcan->mtx);
1282 #endif
1283  io_can_chan_read_post(read, -1, errnum2c(ERRNUM_BADF));
1284  } else if (vcan->stopped) {
1285 #if !LELY_NO_THREADS
1286  mtx_unlock(&vcan->mtx);
1287 #endif
1288  io_can_chan_read_post(read, -1, errnum2c(ERRNUM_NETDOWN));
1289  } else {
1290  int post_read = !vcan->read_posted
1291  && sllist_empty(&vcan->read_queue);
1292  sllist_push_back(&vcan->read_queue, &task->_node);
1293  if (post_read)
1294  vcan->read_posted = 1;
1295 #if !LELY_NO_THREADS
1296  mtx_unlock(&vcan->mtx);
1297 #endif
1298  // cppcheck-suppress duplicateCondition
1299  if (post_read)
1300  ev_exec_post(vcan->read_task.exec, &vcan->read_task);
1301  }
1302 }
1303 
1304 static int
1305 io_vcan_chan_write(io_can_chan_t *chan, const struct can_msg *msg, int timeout)
1306 {
1307  io_can_ctrl_t *ctrl = io_vcan_chan_get_ctrl(chan);
1308  if (!ctrl) {
1310  return -1;
1311  }
1312  return io_vcan_ctrl_write(ctrl, chan, msg, NULL, timeout);
1313 }
1314 
1315 static void
1316 io_vcan_chan_submit_write(io_can_chan_t *chan, struct io_can_chan_write *write)
1317 {
1318  struct io_vcan_chan *vcan = io_vcan_chan_from_chan(chan);
1319  assert(write);
1320  struct ev_task *task = &write->task;
1321 
1322  if (!task->exec)
1323  task->exec = vcan->exec;
1324  ev_exec_on_task_init(task->exec);
1325 
1326 #if !LELY_NO_THREADS
1327  mtx_lock(&vcan->mtx);
1328 #endif
1329  if (vcan->shutdown) {
1330 #if !LELY_NO_THREADS
1331  mtx_unlock(&vcan->mtx);
1332 #endif
1333  io_can_chan_write_post(write, errnum2c(ERRNUM_CANCELED));
1334  } else if (!vcan->ctrl) {
1335 #if !LELY_NO_THREADS
1336  mtx_unlock(&vcan->mtx);
1337 #endif
1338  io_can_chan_write_post(write, errnum2c(ERRNUM_BADF));
1339  } else if (vcan->stopped) {
1340 #if !LELY_NO_THREADS
1341  mtx_unlock(&vcan->mtx);
1342 #endif
1343  io_can_chan_write_post(write, errnum2c(ERRNUM_NETDOWN));
1344  } else {
1345  int post_write = !vcan->write_posted
1346  && sllist_empty(&vcan->write_queue);
1347  sllist_push_back(&vcan->write_queue, &task->_node);
1348  if (post_write)
1349  vcan->write_posted = 1;
1350 #if !LELY_NO_THREADS
1351  mtx_unlock(&vcan->mtx);
1352 #endif
1353  // cppcheck-suppress duplicateCondition
1354  if (post_write)
1355  ev_exec_post(vcan->write_task.exec, &vcan->write_task);
1356  }
1357 }
1358 
1359 static void
1360 io_vcan_chan_svc_shutdown(struct io_svc *svc)
1361 {
1362  struct io_vcan_chan *vcan = io_vcan_chan_from_svc(svc);
1363  io_dev_t *dev = &vcan->dev_vptr;
1364 
1365 #if !LELY_NO_THREADS
1366  mtx_lock(&vcan->mtx);
1367 #endif
1368  int shutdown = !vcan->shutdown;
1369  vcan->shutdown = 1;
1370  if (shutdown)
1371  // Try to abort io_vcan_chan_read_task_func() and
1372  // io_vcan_chan_write_task_func().
1373  io_vcan_chan_do_abort_tasks(vcan);
1374 #if !LELY_NO_THREADS
1375  mtx_unlock(&vcan->mtx);
1376 #endif
1377  // cppcheck-suppress duplicateCondition
1378  if (shutdown)
1379  // Cancel all pending operations.
1380  io_vcan_chan_dev_cancel(dev, NULL);
1381 }
1382 
1383 static void
1384 io_vcan_chan_read_task_func(struct ev_task *task)
1385 {
1386  assert(task);
1387  struct io_vcan_chan *vcan =
1388  structof(task, struct io_vcan_chan, read_task);
1389 
1390 #if !LELY_NO_THREADS
1391  mtx_lock(&vcan->mtx);
1392 #endif
1393  vcan->read_posted = 0;
1394  // Try to process all pending read operations at once.
1395  while ((task = ev_task_from_node(sllist_first(&vcan->read_queue)))) {
1396  // Check if a frame is available in the receive queue.
1397  size_t n = 1;
1398  size_t i = spscring_c_alloc(&vcan->rxring, &n);
1399  if (!n) {
1400  // If the queue is empty, register a wait operation and
1401  // return.
1402  // clang-format off
1403  if (!spscring_c_submit_wait(&vcan->rxring, 1,
1404  io_vcan_chan_signal, vcan))
1405  // clang-format on
1406  continue;
1407  break;
1408  }
1409  sllist_pop_front(&vcan->read_queue);
1410  struct io_vcan_frame *frame = &vcan->rxbuf[i];
1411 
1412  struct io_can_chan_read *read =
1414  if (!frame->is_err && read->msg)
1415  *read->msg = frame->u.msg;
1416  if (frame->is_err && read->err)
1417  *read->err = frame->u.err;
1418  if (read->tp)
1419  *read->tp = frame->ts;
1420  io_can_chan_read_post(read, !frame->is_err, 0);
1421 
1422  spscring_c_commit(&vcan->rxring, 1);
1423  }
1424 #if !LELY_NO_THREADS
1425  mtx_unlock(&vcan->mtx);
1426 #endif
1427 }
1428 
1429 static void
1430 io_vcan_chan_write_task_func(struct ev_task *task)
1431 {
1432  assert(task);
1433  struct io_vcan_chan *vcan =
1434  structof(task, struct io_vcan_chan, write_task);
1435 
1436  int errsv = get_errc();
1437 
1438  struct io_can_chan_write *write = NULL;
1439  int wouldblock = 0;
1440 
1441 #if !LELY_NO_THREADS
1442  mtx_lock(&vcan->mtx);
1443 #endif
1444  vcan->write_posted = 0;
1445  // Try to process all pending write operations at once.
1446  while ((task = vcan->current_write = ev_task_from_node(
1447  sllist_pop_front(&vcan->write_queue)))) {
1449 #if !LELY_NO_THREADS
1450  mtx_unlock(&vcan->mtx);
1451 #endif
1452  // Perform a non-blocking write.
1453  int result = io_vcan_chan_write(
1454  &vcan->chan_vptr, write->msg, 0);
1455  int errc = !result ? 0 : get_errc();
1456  wouldblock = errc == errnum2c(ERRNUM_AGAIN)
1458  if (!wouldblock)
1459  // The operation succeeded or failed immediately.
1460  io_can_chan_write_post(write, errc);
1461 #if !LELY_NO_THREADS
1462  mtx_lock(&vcan->mtx);
1463 #endif
1464  if (task == vcan->current_write) {
1465  // Put the write operation back on the queue if it would
1466  // block, unless it was canceled.
1467  if (wouldblock) {
1469  &task->_node);
1470  task = NULL;
1471  }
1472  vcan->current_write = NULL;
1473  }
1474  assert(!vcan->current_write);
1475  // Stop if the operation would block, or this task has been
1476  // reposted.
1477  if (wouldblock || vcan->write_posted)
1478  break;
1479  }
1480  int post_write = !vcan->write_posted
1481  && !sllist_empty(&vcan->write_queue) && !vcan->shutdown;
1482  if (post_write)
1483  vcan->write_posted = 1;
1484 #if !LELY_NO_THREADS
1485  mtx_unlock(&vcan->mtx);
1486 #endif
1487 
1488  if (task && wouldblock)
1489  // The operation would block but was canceled before it could be
1490  // requeued.
1491  io_can_chan_write_post(io_can_chan_write_from_task(task),
1493 
1494  if (post_write)
1495  ev_exec_post(vcan->write_task.exec, &vcan->write_task);
1496 
1497  set_errc(errsv);
1498 }
1499 
1500 static inline struct io_vcan_chan *
1501 io_vcan_chan_from_dev(const io_dev_t *dev)
1502 {
1503  assert(dev);
1504 
1505  return structof(dev, struct io_vcan_chan, dev_vptr);
1506 }
1507 
1508 static inline struct io_vcan_chan *
1509 io_vcan_chan_from_chan(const io_can_chan_t *chan)
1510 {
1511  assert(chan);
1512 
1513  return structof(chan, struct io_vcan_chan, chan_vptr);
1514 }
1515 
1516 static inline struct io_vcan_chan *
1517 io_vcan_chan_from_svc(const struct io_svc *svc)
1518 {
1519  assert(svc);
1520 
1521  return structof(svc, struct io_vcan_chan, svc);
1522 }
1523 
1524 static void
1525 io_vcan_chan_signal(struct spscring *ring, void *arg)
1526 {
1527  (void)ring;
1528  struct io_vcan_chan *vcan = arg;
1529  assert(vcan);
1530 
1531 #if !LELY_NO_THREADS
1532  mtx_lock(&vcan->mtx);
1533 #endif
1534  int post_read = !vcan->read_posted && !sllist_empty(&vcan->read_queue);
1535  if (post_read)
1536  vcan->read_posted = 1;
1537 #if !LELY_NO_THREADS
1538  cnd_broadcast(&vcan->cond);
1539  mtx_unlock(&vcan->mtx);
1540 #endif
1541  // cppcheck-suppress duplicateCondition
1542  if (post_read)
1543  ev_exec_post(vcan->read_task.exec, &vcan->read_task);
1544 }
1545 
1546 static void
1547 io_vcan_chan_do_pop(struct io_vcan_chan *vcan, struct sllist *read_queue,
1548  struct sllist *write_queue, struct ev_task *task)
1549 {
1550  assert(vcan);
1551  assert(read_queue);
1552  assert(write_queue);
1553 
1554  if (!task) {
1557  } else if (sllist_remove(&vcan->read_queue, &task->_node)) {
1558  sllist_push_back(read_queue, &task->_node);
1559  } else if (sllist_remove(&vcan->write_queue, &task->_node)) {
1560  sllist_push_back(write_queue, &task->_node);
1561  }
1562 }
1563 
1564 static size_t
1565 io_vcan_chan_do_abort_tasks(struct io_vcan_chan *vcan)
1566 {
1567  assert(vcan);
1568 
1569  size_t n = 0;
1570 
1571  // Try to abort io_vcan_chan_read_task_func().
1572  // clang-format off
1573  if (vcan->read_posted && ev_exec_abort(vcan->read_task.exec,
1574  &vcan->read_task)) {
1575  // clang-format on
1576  vcan->read_posted = 0;
1577  n++;
1578  }
1579 
1580  // Try to abort io_vcan_chan_write_task_func().
1581  // clang-format off
1582  if (vcan->write_posted && ev_exec_abort(vcan->write_task.exec,
1583  &vcan->write_task)) {
1584  // clang-format on
1585  vcan->write_posted = 0;
1586  n++;
1587  }
1588 
1589  return n;
1590 }
1591 
1592 #endif // !LELY_NO_MALLOC
ctx.h
io_vcan_ctrl::list
struct sllist list
The list of registered virtual CAN channels.
Definition: vcan.c:115
LELY_IO_VCAN_BITRATE
#define LELY_IO_VCAN_BITRATE
The default bitrate of a virtual CAN bus.
Definition: vcan.c:44
can_msg::flags
uint_least8_t flags
The flags (any combination of CAN_FLAG_IDE, CAN_FLAG_RTR, CAN_FLAG_FDF, CAN_FLAG_BRS and CAN_FLAG_ESI...
Definition: msg.h:94
ev_task_from_node
struct ev_task * ev_task_from_node(struct slnode *node)
Converts a pointer to a node in a queue to the address of the task containing the node.
Definition: task.c:32
ev_exec_t
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition: ev.h:29
mtx_destroy
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
Definition: threads-pthread.c:113
spscring.h
io_vcan_chan::svc
struct io_svc svc
The I/O service representing the channel.
Definition: vcan.c:184
sllist_remove
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
Definition: sllist.c:46
io_vcan_chan_create
io_can_chan_t * io_vcan_chan_create(io_ctx_t *ctx, ev_exec_t *exec, size_t rxlen)
Creates a new virtual CAN channel.
Definition: vcan.c:573
io_can_ctrl_vtbl
Definition: can.h:139
CAN_FLAG_BRS
@ CAN_FLAG_BRS
The Bit Rate Switch (BRS) flag (only available in CAN FD format frames).
Definition: msg.h:62
sllist_first
struct slnode * sllist_first(const struct sllist *list)
Returns a pointer to the first node in a singly-linked list.
Definition: sllist.h:271
io_can_chan_read_from_task
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
spscring_c_commit
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
io_vcan_chan::stopped
unsigned stopped
A flag indicating the virtual CAN controller is stopped.
Definition: vcan.c:222
CAN_STATE_ACTIVE
@ CAN_STATE_ACTIVE
The error active state (TX/RX error count < 128).
Definition: err.h:30
io_vcan_chan::write_posted
unsigned write_posted
A flag indicating whether write_task has been posted to exec.
Definition: vcan.c:226
IO_CAN_BUS_FLAG_ERR
@ IO_CAN_BUS_FLAG_ERR
Reception of error frames is enabled.
Definition: can.h:39
io_svc_vtbl
The virtual table of an I/O service.
Definition: ctx.h:67
io_vcan_chan::mtx
mtx_t mtx
The mutex protecting the channel and the queues of pending operations.
Definition: vcan.c:202
io_vcan_chan::exec
ev_exec_t * exec
A pointer to the executor used to execute all I/O tasks.
Definition: vcan.c:188
io_vcan_chan::write_task
struct ev_task write_task
The task responsible for initiating write operations.
Definition: vcan.c:192
can_msg
A CAN or CAN FD format frame.
Definition: msg.h:87
IO_SVC_INIT
#define IO_SVC_INIT(vptr)
The static initializer for io_svc.
Definition: ctx.h:57
threads.h
io_dev_vtbl
Definition: dev.h:41
io_can_chan_write::task
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the write operation.
Definition: can.h:121
io_vcan_chan_get_ctrl
io_can_ctrl_t * io_vcan_chan_get_ctrl(const io_can_chan_t *chan)
Returns a pointer to the virtual CAN controller with which a virtual CAN channel is registered,...
Definition: vcan.c:609
util.h
diag.h
ERRNUM_NETDOWN
@ ERRNUM_NETDOWN
Network is down.
Definition: errnum.h:151
io_vcan_chan::node
struct slnode node
The node of the channel in the list of the virtual CAN controller.
Definition: vcan.c:218
io_can_chan_vtbl
Definition: can.h:149
io_vcan_ctrl::data
int data
The data bitrate.
Definition: vcan.c:111
io_vcan_ctrl::ctrl_vptr
const struct io_can_ctrl_vtbl * ctrl_vptr
A pointer to the virtual table for the CAN controller interface.
Definition: vcan.c:86
io_can_chan_write::errc
int errc
The error number, obtained as if by get_errc(), if an error occurred or the operation was canceled.
Definition: can.h:126
mtx_lock
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
Definition: threads-pthread.c:150
sllist_push_front
void sllist_push_front(struct sllist *list, struct slnode *node)
Pushes a node to the front of a singly-linked list.
Definition: sllist.h:221
spscring_c_abort_wait
int spscring_c_abort_wait(struct spscring *ring)
Aborts a wait operation previously registered with spscring_c_submit_wait().
Definition: spscring.c:368
get_errc
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:932
io_clock_gettime
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
io_ctx_insert
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
io_vcan_chan::read_posted
unsigned read_posted
A flag indicating whether read_task has been posted to exec.
Definition: vcan.c:224
errno2c
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:46
io_vcan_ctrl::nominal
int nominal
The nominal bitrate.
Definition: vcan.c:109
spscring_c_alloc
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
io_vcan_chan::read_task
struct ev_task read_task
The task responsible for initiating read operations.
Definition: vcan.c:190
spscring_c_submit_wait
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
timespec_add_msec
void timespec_add_msec(struct timespec *tp, uint_least64_t msec)
Adds msec milliseconds to the time at tp.
Definition: time.h:141
io_vcan_chan_destroy
void io_vcan_chan_destroy(io_can_chan_t *chan)
Destroys a virtual CAN channel.
Definition: vcan.c:600
can_err
A CAN error frame.
Definition: err.h:28
spscring_p_alloc
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
io_can_chan_read
A CAN channel read operation.
Definition: can.h:74
sllist_append
struct sllist * sllist_append(struct sllist *dst, struct sllist *src)
Appends the singly-linked list at src to the one at dst.
Definition: sllist.h:257
io_vcan_ctrl_write_msg
int io_vcan_ctrl_write_msg(io_can_ctrl_t *ctrl, const struct can_msg *msg, int timeout)
Writes a CAN frame to a all virtual CAN channels registered with a virtual CAN controller.
Definition: vcan.c:419
mtx_t
pthread_mutex_t mtx_t
A complete object type that holds an identifier for a mutex.
Definition: threads.h:102
cnd_t
pthread_cond_t cnd_t
A complete object type that holds an identifier for a condition variable.
Definition: threads.h:78
can.h
thrd_success
@ thrd_success
Indicates that the requested operation succeeded.
Definition: threads.h:121
cnd_timedwait
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
Atomically unlocks the mutex at mtx and endeavors to block until the condition variable at cond is si...
Definition: threads-pthread.c:91
io_vcan_chan::chan_vptr
const struct io_can_chan_vtbl * chan_vptr
A pointer to the virtual table for the CAN channel interface.
Definition: vcan.c:182
io_vcan_ctrl::stopped
int stopped
A flag indicating whether the controller is stopped.
Definition: vcan.c:107
io_can_chan_read::msg
struct can_msg * msg
The address at which to store the CAN frame.
Definition: can.h:80
spscring_init
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
IO_CAN_BUS_FLAG_FDF
@ IO_CAN_BUS_FLAG_FDF
FD Format (formerly Extended Data Length) support is enabled.
Definition: can.h:42
mtx_unlock
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
Definition: threads-pthread.c:183
ERRNUM_BADF
@ ERRNUM_BADF
Bad file descriptor.
Definition: errnum.h:93
io_vcan_chan::rxring
struct spscring rxring
The ring buffer used to control the receive queue.
Definition: vcan.c:194
ERRNUM_CANCELED
@ ERRNUM_CANCELED
Operation canceled.
Definition: errnum.h:99
io_vcan_chan::ctrl
io_can_ctrl_t * ctrl
A pointer to the virtual CAN controller with which this channel is registered.
Definition: vcan.c:213
io_can_chan_write
A CAN channel write operation.
Definition: can.h:110
io_can_chan_t
const struct io_can_chan_vtbl *const io_can_chan_t
An abstract CAN channel.
Definition: can.h:59
io_can_chan_write::msg
const struct can_msg * msg
A pointer to the CAN frame to be written.
Definition: can.h:116
spscring_p_submit_wait
int spscring_p_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:163
set_errnum
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:424
io_vcan_chan::current_write
struct ev_task * current_write
The write operation currently being executed.
Definition: vcan.c:232
io_vcan_ctrl::cond
cnd_t cond
The condition variable used to wake up blocked synchronous write operations.
Definition: vcan.c:104
set_errc
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:944
io_vcan_ctrl_create
io_can_ctrl_t * io_vcan_ctrl_create(io_clock_t *clock, int flags, int nominal, int data, int state)
Creates a new virtual CAN controller.
Definition: vcan.c:352
sllist_empty
int sllist_empty(const struct sllist *list)
Returns 1 if the singly-linked list is empty, and 0 if not.
Definition: sllist.h:202
CAN_STATE_STOPPED
@ CAN_STATE_STOPPED
The device is stopped.
Definition: err.h:38
DIAG_WARNING
@ DIAG_WARNING
A warning.
Definition: diag.h:55
cnd_wait
int cnd_wait(cnd_t *cond, mtx_t *mtx)
Atomically unlocks the mutex at mtx and endeavors to block until the condition variable at cond is si...
Definition: threads-pthread.c:102
errnum2c
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition: errnum.c:810
io_vcan_chan::write_queue
struct sllist write_queue
The queue containing pending write operations.
Definition: vcan.c:230
ev_task_queue_abort
size_t ev_task_queue_abort(struct sllist *queue)
Aborts the tasks in queue by invoking ev_exec_on_task_fini() for each of them.
Definition: task.c:55
spscring_p_abort_wait
int spscring_p_abort_wait(struct spscring *ring)
Aborts a wait operation previously registered with spscring_p_submit_wait().
Definition: spscring.c:204
ERRNUM_INVAL
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:132
stdint.h
io_svc
An I/O service.
Definition: ctx.h:49
sllist_init
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
Definition: sllist.h:194
sllist_pop_front
struct slnode * sllist_pop_front(struct sllist *list)
Pops a node from the front of a singly-linked list.
Definition: sllist.h:243
cnd_destroy
void cnd_destroy(cnd_t *cond)
Releases all resources used by the condition variable at cond.
Definition: threads-pthread.c:63
thrd_timedout
@ thrd_timedout
Indicates that the time specified in the call was reached without acquiring the requested resource.
Definition: threads.h:128
ev_exec_abort
size_t ev_exec_abort(ev_exec_t *exec, struct ev_task *task)
Aborts the specified task submitted to *exec, if it has not yet begun executing, or all pending tasks...
Definition: exec.h:136
ERRNUM_WOULDBLOCK
@ ERRNUM_WOULDBLOCK
Operation would block.
Definition: errnum.h:233
io_vcan_frame
Definition: vcan.c:55
io_vcan_chan::rxbuf
struct io_vcan_frame * rxbuf
The receive queue.
Definition: vcan.c:196
io_vcan_ctrl::state
int state
The state of the virtual CAN bus.
Definition: vcan.c:113
cnd_init
int cnd_init(cnd_t *cond)
Creates a condition variable.
Definition: threads-pthread.c:69
io_vcan_chan::dev_vptr
const struct io_dev_vtbl * dev_vptr
A pointer to the virtual table for the I/O device interface.
Definition: vcan.c:180
can_err::state
int state
The state of the CAN node (one of CAN_STATE_ACTIVE, CAN_STATE_PASSIVE or CAN_STATE_BUSOFF).
Definition: err.h:33
io_ctx_remove
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
io_vcan_ctrl_destroy
void io_vcan_ctrl_destroy(io_can_ctrl_t *ctrl)
Destroys a virtual CAN controller.
Definition: vcan.c:381
time.h
io_can_chan_read::tp
struct timespec * tp
The address at which to store the system time at which the CAN frame or CAN error frame was received.
Definition: can.h:93
slnode_init
void slnode_init(struct slnode *node)
Initializes a node in a singly-linked list.
Definition: sllist.h:186
diag
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:171
timespec_get
int timespec_get(struct timespec *ts, int base)
Sets the interval at ts to hold the current calendar time based on the specified time base.
Definition: time.c:32
thrd_yield
void thrd_yield(void)
Endeavors to permit other threads to run, even if the current thread would ordinarily continue to run...
Definition: threads-pthread.c:277
sllist
A singly-linked list.
Definition: sllist.h:52
vcan.h
io_vcan_ctrl_write_err
int io_vcan_ctrl_write_err(io_can_ctrl_t *ctrl, const struct can_err *err, int timeout)
Writes a CAN error frame to a all virtual CAN channels registered with a virtual CAN controller.
Definition: vcan.c:426
sllist_foreach
#define sllist_foreach(list, node)
Iterates in order over each node in a singly-linked list.
Definition: sllist.h:183
LELY_IO_VCAN_RXLEN
#define LELY_IO_VCAN_RXLEN
The default receive queue length (in number of CAN frames) of a vritual CAN channel.
Definition: vcan.c:52
IO_CAN_BUS_FLAG_BRS
@ IO_CAN_BUS_FLAG_BRS
Bit Rate Switch support is enabled.
Definition: can.h:44
io_can_chan_read::err
struct can_err * err
The address at which to store the CAN error frame.
Definition: can.h:86
io_can_chan_write_from_task
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
io_vcan_ctrl
The implementation of a virtual CAN controller.
Definition: vcan.c:84
structof
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
Definition: util.h:93
ev_task
An executable task.
Definition: task.h:41
io_vcan_chan
The implementation of a virtual CAN channel.
Definition: vcan.c:178
io_vcan_chan::cond
cnd_t cond
The condition variable used to wake up blocked synchronous read operations.
Definition: vcan.c:207
io_vcan_ctrl_set_state
void io_vcan_ctrl_set_state(io_can_ctrl_t *ctrl, int state)
Sets the state of a virtual CAN bus: one of CAN_STATE_ACTIVE, CAN_STATE_PASSIVE, CAN_STATE_BUSOFF,...
Definition: vcan.c:390
io_vcan_chan_open
void io_vcan_chan_open(io_can_chan_t *chan, io_can_ctrl_t *ctrl)
Opens a virtual CAN channel by registering it with the specified virtual CAN controller.
Definition: vcan.c:625
io_dev_t
const struct io_dev_vtbl *const io_dev_t
An abstract I/O device.
Definition: dev.h:35
CAN_FLAG_FDF
@ CAN_FLAG_FDF
The FD Format (FDF) flag, formerly known as Extended Data Length (EDL).
Definition: msg.h:54
EV_TASK_INIT
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
Definition: task.h:53
io_vcan_ctrl::flags
int flags
The flags specifying which CAN bus features are enabled.
Definition: vcan.c:93
ev_exec_on_task_init
void ev_exec_on_task_init(ev_exec_t *exec)
Indicates to the specified executor that a task will be submitted for execution in the future.
Definition: exec.h:106
cnd_broadcast
int cnd_broadcast(cnd_t *cond)
Unblocks all of the threads that are blocked on the condition variable at cond at the time of the cal...
Definition: threads-pthread.c:52
io_vcan_chan::read_queue
struct sllist read_queue
The queue containing pending read operations.
Definition: vcan.c:228
io_vcan_chan_is_open
int io_vcan_chan_is_open(const io_can_chan_t *chan)
Returns 1 if the CAN channel is open and 0 if not.
Definition: vcan.c:633
io_ctx
Definition: ctx.c:38
io_vcan_chan_close
void io_vcan_chan_close(io_can_chan_t *chan)
Closes a virtual CAN channel.
Definition: vcan.c:639
spscring
A single-producer, single-consumer ring buffer.
Definition: spscring.h:63
ev_exec_post
void ev_exec_post(ev_exec_t *exec, struct ev_task *task)
Submits *task to *exec for execution.
Definition: exec.h:124
io_can_chan_read::task
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the read operation.
Definition: can.h:98
stdlib.h
spscring_p_commit
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
slnode
A node in a singly-linked list.
Definition: sllist.h:40
sllist_push_back
void sllist_push_back(struct sllist *list, struct slnode *node)
Pushes a node to the back of a singly-linked list.
Definition: sllist.h:232
io_vcan_chan::shutdown
unsigned shutdown
A flag indicating whether the I/O service has been shut down.
Definition: vcan.c:220
io_clock_t
const struct io_clock_vtbl *const io_clock_t
An abstract clock.
Definition: clock.h:36
mtx_init
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:
Definition: threads-pthread.c:119
ev_task::exec
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
Definition: task.h:43
mtx_plain
@ mtx_plain
A mutex type that supports neither timeout nor test and return.
Definition: threads.h:109
ERRNUM_AGAIN
@ ERRNUM_AGAIN
Resource unavailable, try again.
Definition: errnum.h:89
io_vcan_ctrl::clock
io_clock_t * clock
A pointer to the clock used to obtain the timestamp when sending CAN frames.
Definition: vcan.c:91
io_vcan_chan::ctx
io_ctx_t * ctx
A pointer to the I/O context with which the channel is registered.
Definition: vcan.c:186
io_vcan_ctrl::mtx
mtx_t mtx
The mutex protecting the controller and the list of virtual CAN channels.
Definition: vcan.c:99
io_can_ctrl_t
const struct io_can_ctrl_vtbl *const io_can_ctrl_t
An abstract CAN controller.
Definition: can.h:56