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