26 #if !LELY_NO_STDIO && defined(__linux__)
46 #include <linux/can/raw.h>
47 #include <linux/sockios.h>
48 #include <sys/ioctl.h>
50 #include "../posix/fd.h"
55 #ifndef LELY_IO_CAN_RXLEN
57 #define LELY_IO_CAN_RXLEN 1024
62 struct can_frame frame;
64 struct canfd_frame frame;
70 static int io_can_fd_set_default(
int fd);
72 static int io_can_fd_read(
int fd,
struct can_frame *frame,
size_t *pnbytes,
73 int *pflags,
struct timespec *tp,
int timeout);
75 static int io_can_fd_read(
int fd,
struct canfd_frame *frame,
size_t *pnbytes,
76 int *pflags,
struct timespec *tp,
int timeout);
79 static int io_can_fd_write(
int fd,
const struct can_frame *frame,
size_t nbytes,
82 static int io_can_fd_write(
int fd,
const struct canfd_frame *frame,
83 size_t nbytes,
int timeout);
85 static int io_can_fd_write_msg(
int fd,
const struct can_msg *msg,
int timeout);
89 static size_t io_can_chan_impl_dev_cancel(
io_dev_t *dev,
struct ev_task *task);
90 static size_t io_can_chan_impl_dev_abort(
io_dev_t *dev,
struct ev_task *task);
93 static const struct io_dev_vtbl io_can_chan_impl_dev_vtbl = {
94 &io_can_chan_impl_dev_get_ctx,
95 &io_can_chan_impl_dev_get_exec,
96 &io_can_chan_impl_dev_cancel,
97 &io_can_chan_impl_dev_abort
102 static int io_can_chan_impl_get_flags(
const io_can_chan_t *chan);
104 struct can_err *err,
struct timespec *tp,
int timeout);
105 static void io_can_chan_impl_submit_read(
107 static int io_can_chan_impl_write(
109 static void io_can_chan_impl_submit_write(
114 &io_can_chan_impl_get_dev,
115 &io_can_chan_impl_get_flags,
116 &io_can_chan_impl_read,
117 &io_can_chan_impl_submit_read,
118 &io_can_chan_impl_write,
119 &io_can_chan_impl_submit_write
123 static void io_can_chan_impl_svc_shutdown(
struct io_svc *svc);
126 static const struct io_svc_vtbl io_can_chan_impl_svc_vtbl = {
128 &io_can_chan_impl_svc_shutdown
197 static void io_can_chan_impl_watch_func(
199 static void io_can_chan_impl_rxbuf_task_func(
struct ev_task *task);
200 static void io_can_chan_impl_read_task_func(
struct ev_task *task);
201 static void io_can_chan_impl_write_task_func(
struct ev_task *task);
210 static void io_can_chan_impl_c_signal(
struct spscring *ring,
void *arg);
217 struct sllist *queue,
int *pwouldblock);
221 static size_t io_can_chan_impl_do_abort_tasks(
struct io_can_chan_impl *impl);
223 static int io_can_chan_impl_set_fd(
227 io_can_chan_alloc(
void)
239 io_can_chan_free(
void *ptr)
242 free(io_can_chan_impl_from_chan(ptr));
257 impl->
dev_vptr = &io_can_chan_impl_dev_vtbl;
258 impl->
chan_vptr = &io_can_chan_impl_vtbl;
268 &io_can_chan_impl_watch_func);
271 impl->
exec, &io_can_chan_impl_rxbuf_task_func);
273 impl->
exec, &io_can_chan_impl_read_task_func);
275 impl->
exec, &io_can_chan_impl_write_task_func);
278 if ((errsv = pthread_mutex_init(&impl->
c_mtx, NULL)))
279 goto error_init_c_mtx;
286 goto error_alloc_rxbuf;
290 if ((errsv = pthread_mutex_init(&impl->
mtx, NULL)))
320 pthread_mutex_destroy(&impl->
c_mtx);
335 io_can_chan_impl_svc_shutdown(&impl->
svc);
339 pthread_mutex_lock(&impl->
c_mtx);
341 pthread_mutex_unlock(&impl->
c_mtx);
344 pthread_mutex_lock(&impl->
mtx);
349 if (io_can_chan_impl_do_abort_tasks(impl))
351 pthread_mutex_unlock(&impl->
mtx);
355 "io_can_chan_fini() invoked with pending operations");
358 pthread_mutex_lock(&impl->
mtx);
360 pthread_mutex_unlock(&impl->
mtx);
364 if (impl->
fd != -1) {
371 pthread_mutex_destroy(&impl->
mtx);
377 pthread_mutex_destroy(&impl->
c_mtx);
402 io_can_chan_free((
void *)chan);
412 io_can_chan_fini(chan);
413 io_can_chan_free((
void *)chan);
423 pthread_mutex_lock((pthread_mutex_t *)&impl->
mtx);
427 pthread_mutex_unlock((pthread_mutex_t *)&impl->
mtx);
444 int fd = socket(AF_CAN, SOCK_RAW | SOCK_CLOEXEC, CAN_RAW);
450 struct sockaddr_can addr = { .can_family = AF_CAN,
453 if (bind(fd, (
struct sockaddr *)&addr,
sizeof(addr)) == -1) {
459 can_err_mask_t optval = CAN_ERR_MASK;
461 if (setsockopt(fd, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &optval,
462 sizeof(optval)) == -1) {
465 goto error_setsockopt;
473 if (setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &optval,
474 sizeof(optval)) == -1) {
477 goto error_setsockopt;
482 if (io_can_fd_set_default(fd) == -1) {
484 goto error_set_default;
487 fd = io_can_chan_impl_set_fd(impl, fd, flags);
507 struct sockaddr_can addr = { .can_family = AF_UNSPEC };
508 socklen_t addrlen =
sizeof(addr);
509 if (getsockname(fd, (
struct sockaddr *)&addr, &addrlen) == -1)
511 if (addrlen <
sizeof(addr) || addr.can_family != AF_CAN) {
515 unsigned int ifindex = addr.can_ifindex;
518 if (io_can_attr_get(&attr, ifindex) == -1)
520 int flags = attr.flags;
523 can_err_mask_t optval = 0;
524 socklen_t optlen =
sizeof(optval);
526 if (getsockopt(fd, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &optval,
530 if (optval & CAN_ERR_MASK)
540 socklen_t optlen =
sizeof(optval);
542 if (!getsockopt(fd, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &optval,
550 if (io_can_fd_set_default(fd) == -1)
553 fd = io_can_chan_impl_set_fd(impl, fd, flags);
565 return io_can_chan_impl_set_fd(impl, -1, 0);
578 return fd != -1 ? close(
fd) : 0;
582 io_can_fd_set_default(
int fd)
589 if (setsockopt(
fd, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &optval,
590 sizeof(optval)) == -1)
598 if (setsockopt(
fd, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &optval,
599 sizeof(optval)) == -1)
608 if (setsockopt(
fd, SOL_SOCKET, SO_SNDBUF, &optval,
sizeof(optval))
618 io_can_fd_read(
int fd,
struct can_frame *frame,
size_t *pnbytes,
int *pflags,
619 struct timespec *tp,
int timeout)
621 io_can_fd_read(
int fd,
struct canfd_frame *frame,
size_t *pnbytes,
int *pflags,
622 struct timespec *tp,
int timeout)
625 struct iovec iov = { .iov_base = (
void *)frame,
626 .iov_len =
sizeof(*frame) };
627 struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
635 if (result == CAN_MTU)
637 if (result == CAN_MTU || result == CANFD_MTU)
648 *pflags = msg.msg_flags;
651 if (msg.msg_flags & MSG_CONFIRM) {
653 *tp = (
struct timespec){ 0, 0 };
655 struct timeval tv = { 0, 0 };
656 if (ioctl(fd, SIOCGSTAMP, &tv) == -1)
658 tp->tv_sec = tv.tv_sec;
659 tp->tv_nsec = tv.tv_usec * 1000;
668 io_can_fd_write(
int fd,
const struct can_frame *frame,
size_t nbytes,
671 io_can_fd_write(
int fd,
const struct canfd_frame *frame,
size_t nbytes,
675 struct iovec iov = { .iov_base = (
void *)frame, .iov_len = nbytes };
676 struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
682 io_can_fd_write_msg(
int fd,
const struct can_msg *msg,
int timeout)
694 frame.nbytes = CANFD_MTU;
702 frame.nbytes = CAN_MTU;
707 return io_can_fd_write(fd, &frame.frame, frame.nbytes, timeout);
711 io_can_chan_impl_dev_get_ctx(
const io_dev_t *dev)
719 io_can_chan_impl_dev_get_exec(
const io_dev_t *dev)
733 struct sllist read_queue, write_queue, confirm_queue;
739 pthread_mutex_lock(&impl->
mtx);
741 io_can_chan_impl_do_pop(
742 impl, &read_queue, &write_queue, &confirm_queue, task);
749 pthread_mutex_unlock(&impl->
mtx);
752 size_t nread = io_can_chan_read_queue_post(&read_queue, -1, ECANCELED);
753 n = n < SIZE_MAX - nread ? n + nread : SIZE_MAX;
754 size_t nwrite = io_can_chan_write_queue_post(&write_queue, ECANCELED);
755 n = n < SIZE_MAX - nwrite ? n + nwrite : SIZE_MAX;
757 io_can_chan_write_queue_post(&confirm_queue, ECANCELED);
758 n = n < SIZE_MAX - nconfirm ? n + nconfirm : SIZE_MAX;
772 pthread_mutex_lock(&impl->
mtx);
774 io_can_chan_impl_do_pop(impl, &queue, &queue, &queue, task);
776 pthread_mutex_unlock(&impl->
mtx);
795 pthread_mutex_lock((pthread_mutex_t *)&impl->
mtx);
799 pthread_mutex_unlock((pthread_mutex_t *)&impl->
mtx);
806 struct can_err *err,
struct timespec *tp,
int timeout)
813 pthread_mutex_lock(&impl->
c_mtx);
821 frame = &impl->
rxbuf[i];
825 pthread_mutex_unlock(&impl->
c_mtx);
826 pthread_mutex_lock(&impl->
mtx);
831 pthread_mutex_unlock(&impl->
mtx);
835 if (io_can_fd_read(fd, &frame->frame, &frame->nbytes, &flags,
836 &frame->ts, timeout) < 0)
840 if (!(flags & MSG_CONFIRM))
843 void *src = &frame->frame;
846 if (frame->nbytes == CANFD_MTU)
855 pthread_mutex_lock(&impl->
mtx);
857 io_can_chan_impl_do_confirm(impl, &queue, &msg);
859 pthread_mutex_unlock(&impl->
mtx);
867 pthread_mutex_lock(&impl->
c_mtx);
871 void *data = &frame->frame;
872 int is_err = can_frame2can_err(data, err);
873 if (!is_err && msg) {
875 if (frame->nbytes == CANFD_MTU)
887 pthread_mutex_unlock(&impl->
c_mtx);
891 return is_err == -1 ? -1 : !is_err;
907 pthread_mutex_lock(&impl->
mtx);
911 pthread_mutex_unlock(&impl->
mtx);
913 io_can_chan_read_post(read, -1, ECANCELED);
921 pthread_mutex_unlock(&impl->
mtx);
930 io_can_chan_impl_write(
944 pthread_mutex_lock(&impl->
mtx);
949 pthread_mutex_unlock(&impl->
mtx);
957 pthread_mutex_unlock(&impl->
mtx);
960 return io_can_fd_write_msg(
fd, msg, timeout);
964 io_can_chan_impl_submit_write(
986 pthread_mutex_lock(&impl->
mtx);
990 pthread_mutex_unlock(&impl->
mtx);
992 io_can_chan_write_post(write, ECANCELED);
994 }
else if ((flags & impl->
flags) != flags) {
996 pthread_mutex_unlock(&impl->
mtx);
998 io_can_chan_write_post(write, EINVAL);
1006 #if !LELY_NO_THREADS
1007 pthread_mutex_unlock(&impl->
mtx);
1016 io_can_chan_impl_svc_shutdown(
struct io_svc *svc)
1021 #if !LELY_NO_THREADS
1022 pthread_mutex_lock(&impl->
mtx);
1036 io_can_chan_impl_do_abort_tasks(impl);
1038 #if !LELY_NO_THREADS
1039 pthread_mutex_unlock(&impl->
mtx);
1044 io_can_chan_impl_dev_cancel(dev, NULL);
1054 #if !LELY_NO_THREADS
1055 pthread_mutex_lock(&impl->
mtx);
1064 &impl->
watch) == -1) {
1087 #if !LELY_NO_THREADS
1088 pthread_mutex_unlock(&impl->
mtx);
1098 io_can_chan_impl_rxbuf_task_func(
struct ev_task *task)
1113 #if !LELY_NO_THREADS
1114 pthread_mutex_lock(&impl->
mtx);
1125 #if !LELY_NO_THREADS
1126 pthread_mutex_unlock(&impl->
mtx);
1135 frame = &impl->
rxbuf[i];
1139 result = io_can_fd_read(fd, &frame->frame, &frame->nbytes,
1142 errc = !result ? 0 : errno;
1143 wouldblock = errc == EAGAIN || errc == EWOULDBLOCK;
1148 if (!result && (
flags & MSG_CONFIRM)) {
1149 void *src = &frame->frame;
1151 if (frame->nbytes == CANFD_MTU)
1159 if (!result && !(
flags & MSG_CONFIRM))
1162 #if !LELY_NO_THREADS
1163 pthread_mutex_lock(&impl->
mtx);
1166 if (!result &&
flags & MSG_CONFIRM)
1167 io_can_chan_impl_do_confirm(impl, &queue, &msg);
1171 if (!impl->
poll || result < 0)
1175 if (result < 0 && !wouldblock) {
1176 io_can_chan_impl_do_read(impl, &queue, NULL);
1182 read->
r.
errc = errc;
1193 if (post_rxbuf && impl->
poll && wouldblock) {
1206 #if !LELY_NO_THREADS
1207 pthread_mutex_unlock(&impl->
mtx);
1219 io_can_chan_impl_read_task_func(
struct ev_task *
task)
1228 #if !LELY_NO_THREADS
1229 pthread_mutex_lock(&impl->
mtx);
1233 io_can_chan_impl_do_read(impl, &queue, &wouldblock);
1238 if (post_read && wouldblock) {
1239 #if !LELY_NO_THREADS
1240 pthread_mutex_lock(&impl->
c_mtx);
1245 io_can_chan_impl_c_signal, impl);
1246 #if !LELY_NO_THREADS
1247 pthread_mutex_unlock(&impl->
c_mtx);
1260 #if !LELY_NO_THREADS
1261 pthread_mutex_unlock(&impl->
mtx);
1275 io_can_chan_impl_write_task_func(
struct ev_task *task)
1285 #if !LELY_NO_THREADS
1286 pthread_mutex_lock(&impl->
mtx);
1293 #if !LELY_NO_THREADS
1294 pthread_mutex_unlock(&impl->
mtx);
1298 int result = io_can_fd_write_msg(fd, write->
msg,
1300 int errc = !result ? 0 : errno;
1301 wouldblock =
errc == EAGAIN ||
errc == EWOULDBLOCK;
1302 if (!wouldblock &&
errc)
1304 io_can_chan_write_post(write,
errc);
1305 #if !LELY_NO_THREADS
1306 pthread_mutex_lock(&impl->
mtx);
1323 if (!impl->
poll || wouldblock)
1339 if (post_write && impl->
poll && wouldblock) {
1352 #if !LELY_NO_THREADS
1353 pthread_mutex_unlock(&impl->
mtx);
1356 if (
task && wouldblock)
1359 io_can_chan_write_post(
1372 io_can_chan_impl_from_dev(
const io_dev_t *dev)
1388 io_can_chan_impl_from_svc(
const struct io_svc *
svc)
1396 io_can_chan_impl_c_signal(
struct spscring *ring,
void *arg)
1402 #if !LELY_NO_THREADS
1403 pthread_mutex_lock(&impl->
mtx);
1409 #if !LELY_NO_THREADS
1410 pthread_mutex_unlock(&impl->
mtx);
1457 #if !LELY_NO_THREADS
1458 pthread_mutex_lock(&impl->
c_mtx);
1465 #if !LELY_NO_THREADS
1466 pthread_mutex_unlock(&impl->
c_mtx);
1474 void *data = &frame->frame;
1475 int is_err = can_frame2can_err(data, read->
err);
1476 if (!is_err && read->
msg) {
1478 if (frame->nbytes == CANFD_MTU)
1485 *read->
tp = frame->ts;
1488 #if !LELY_NO_THREADS
1489 pthread_mutex_unlock(&impl->
c_mtx);
1500 *pwouldblock = wouldblock;
1533 if (&
task->_node == node) {
1583 assert(!(flags & ~IO_CAN_BUS_FLAG_MASK));
1585 struct sllist read_queue, write_queue, confirm_queue;
1590 #if !LELY_NO_THREADS
1591 pthread_mutex_lock(&impl->
mtx);
1600 #if !LELY_NO_THREADS
1601 pthread_mutex_lock(&impl->
c_mtx);
1605 size_t n = SIZE_MAX;
1609 #if !LELY_NO_THREADS
1610 pthread_mutex_unlock(&impl->
c_mtx);
1617 impl->
flags = flags;
1627 #if !LELY_NO_THREADS
1628 pthread_mutex_unlock(&impl->
mtx);
1631 io_can_chan_read_queue_post(&read_queue, -1, ECANCELED);
1632 io_can_chan_write_queue_post(&write_queue, ECANCELED);
1633 io_can_chan_write_queue_post(&confirm_queue, ECANCELED);
@ CAN_FLAG_FDF
The FD Format (FDF) flag, formerly known as Extended Data Length (EDL).
@ CAN_FLAG_BRS
The Bit Rate Switch (BRS) flag (only available in CAN FD format frames).
This is the internal header file of the SocketCAN rtnetlink attributes functions.
void io_can_chan_destroy(io_can_chan_t *chan)
Destroys a CAN channel.
int io_can_chan_get_handle(const io_can_chan_t *chan)
Returns the SocketCAN file descriptor associated with a CAN channel, or -1 if the channel is closed.
int io_can_chan_close(io_can_chan_t *chan)
Closes the SocketCAN file descriptor associated with a CAN channel.
#define LELY_IO_CAN_RXLEN
The default SocketCAN receive queue length (in number of CAN frames).
int io_can_chan_open(io_can_chan_t *chan, const io_can_ctrl_t *ctrl, int flags)
Opens a CAN channel.
int io_can_chan_release(io_can_chan_t *chan)
Dissociates and returns the SocketCAN file descriptor from a CAN channel.
int io_can_chan_assign(io_can_chan_t *chan, int fd)
Assigns an existing SocketCAN file descriptor to a CAN channel.
io_can_chan_t * io_can_chan_create(io_poll_t *poll, ev_exec_t *exec, size_t rxlen)
Creates a new CAN channel.
int io_can_chan_is_open(const io_can_chan_t *chan)
Returns 1 if the CAN channel is open and 0 if not.
This is the internal header file of the SocketCAN error frame conversion functions.
This is the internal header file of the SocketCAN CAN frame conversion functions.
This header file is part of the I/O library; it contains the I/O context and service declarations.
void io_ctx_insert(io_ctx_t *ctx, struct io_svc *svc)
Registers an I/O service with an I/O context.
#define IO_SVC_INIT(vptr)
The static initializer for io_svc.
void io_ctx_remove(io_ctx_t *ctx, struct io_svc *svc)
Unregisters an I/O service with an I/O context.
This header file is part of the utilities library; it contains the diagnostic declarations.
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
@ IO_EVENT_IN
Data (other than priority data) MAY be read without blocking.
@ IO_EVENT_OUT
Data (bot normal and priority data) MAY be written without blocking.
@ IO_EVENT_ERR
An error has occurred. This event is always reported.
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...
void ev_exec_post(ev_exec_t *exec, struct ev_task *task)
Submits *task to *exec for execution.
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.
ssize_t io_fd_sendmsg(int fd, const struct msghdr *msg, int flags, int timeout)
Equivalent to POSIX sendmsg(fd, msg, flags | MSG_NOSIGNAL), except that if fd is non-blocking (or the...
ssize_t io_fd_recvmsg(int fd, struct msghdr *msg, int flags, int timeout)
Equivalent to POSIX recvmsg(fd, msg, flags), except that if fd is non-blocking (or the implementation...
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
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.
const struct io_can_chan_vtbl *const io_can_chan_t
An abstract CAN channel.
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.
const struct io_can_ctrl_vtbl *const io_can_ctrl_t
An abstract CAN controller.
@ IO_CAN_BUS_FLAG_BRS
Bit Rate Switch support is enabled.
@ IO_CAN_BUS_FLAG_FDF
FD Format (formerly Extended Data Length) support is enabled.
@ IO_CAN_BUS_FLAG_ERR
Reception of error frames is enabled.
#define LELY_IO_RX_TIMEOUT
The default timeout (in milliseconds) for I/O read operations.
#define LELY_IO_TX_TIMEOUT
The default timeout (in milliseconds) for I/O write operations.
This header file is part of the I/O library; it contains the CAN bus declarations for Linux.
unsigned int io_can_ctrl_get_index(const io_can_ctrl_t *ctrl)
Returns the interface index of a CAN controller.
int io_can_ctrl_get_flags(const io_can_ctrl_t *ctrl)
Returns the flags specifying which CAN bus features are enabled.
This is the public header file of the utilities library.
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
int can_msg_cmp(const void *p1, const void *p2)
Compares two CAN or CAN FD format frames.
const struct io_dev_vtbl *const io_dev_t
An abstract I/O device.
This header file is part of the I/O library; it contains the I/O polling declarations for POSIX platf...
io_ctx_t * io_poll_get_ctx(const io_poll_t *poll)
Returns a pointer to the I/O context with which the I/O polling instance is registered.
#define IO_POLL_WATCH_INIT(func)
The static initializer for io_poll_watch.
int io_poll_watch(io_poll_t *poll, io_handle_t handle, struct io_event *event, int keep)
Registers an I/O device with an I/O polling interface and instructs it to watch for certain events.
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
struct sllist * sllist_append(struct sllist *dst, struct sllist *src)
Appends the singly-linked list at src to the one at dst.
void sllist_push_front(struct sllist *list, struct slnode *node)
Pushes a node to the front of a singly-linked list.
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
void sllist_push_back(struct sllist *list, struct slnode *node)
Pushes a node to the back of a singly-linked list.
int sllist_empty(const struct sllist *list)
Returns 1 if the singly-linked list is empty, and 0 if not.
struct slnode * sllist_pop_front(struct sllist *list)
Pops a node from the front of a singly-linked list.
struct slnode * sllist_first(const struct sllist *list)
Returns a pointer to the first node in a singly-linked list.
int can_msg2canfd_frame(const struct can_msg *src, struct canfd_frame *dst)
Converts a can_msg frame to a SocketCAN CAN FD frame.
int can_frame2can_msg(const struct can_frame *src, struct can_msg *dst)
Converts a SocketCAN CAN frame to a can_msg frame.
int canfd_frame2can_msg(const struct canfd_frame *src, struct can_msg *dst)
Converts a SocketCAN CAN FD frame to a can_msg frame.
int can_msg2can_frame(const struct can_msg *src, struct can_frame *dst)
Converts a can_msg frame to a SocketCAN CAN frame.
This header file is part of the utilities library; it contains the single-producer,...
size_t spscring_c_alloc(struct spscring *ring, size_t *psize)
Allocates a consecutive range of indices, including wrapping, in a single-producer,...
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,...
size_t spscring_p_capacity(struct spscring *ring)
Returns the total capacity available for a producer in a single-producer single-consumer ring buffer,...
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...
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...
int spscring_c_abort_wait(struct spscring *ring)
Aborts a wait operation previously registered with spscring_c_submit_wait().
void spscring_init(struct spscring *ring, size_t size)
Initializes a single-producer, single-consumer ring buffer with the specified size.
size_t spscring_p_alloc(struct spscring *ring, size_t *psize)
Allocates a consecutive range of indices, including wrapping, in a single-producer,...
This is the internal header file of the Windows-specific I/O declarations.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
An I/O polling interface.
A CAN or CAN FD format frame.
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...
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
The implementation of a CAN channel.
struct ev_task read_task
The task responsible for initiating read operations.
int fd
The SocketCAN file descriptor.
struct ev_task write_task
The task responsible for initiating write operations.
struct io_can_frame * rxbuf
The receive queue.
struct io_svc svc
The I/O service representing the channel.
struct sllist read_queue
The queue containing pending read operations.
struct ev_task rxbuf_task
The task responsible for filling the receive queue.
io_poll_t * poll
A pointer to the polling instance used to watch for I/O events.
unsigned write_posted
A flag indicating whether write_task has been posted to exec.
int flags
The flags with which fd has been opened.
unsigned read_posted
A flag indicating whether read_task has been posted to exec.
pthread_mutex_t mtx
The mutex protecting the file descriptor, the flags and the queues of pending operations.
struct sllist write_queue
The queue containing pending write operations.
unsigned shutdown
A flag indicating whether the I/O service has been shut down.
ev_exec_t * exec
A pointer to the executor used to execute all I/O tasks.
const struct io_dev_vtbl * dev_vptr
A pointer to the virtual table for the I/O device interface.
struct sllist confirm_queue
The queue containing write operations waiting to be confirmed.
struct ev_task * current_write
The write operation currently being executed.
pthread_mutex_t c_mtx
The mutex protecting the receive queue consumer.
struct io_poll_watch watch
The object used to monitor the file descriptor for I/O events.
const struct io_can_chan_vtbl * chan_vptr
A pointer to the virtual table for the CAN channel interface.
io_ctx_t * ctx
A pointer to the I/O context with which the channel is registered.
int events
The I/O events currently being monitored by poll for fd.
struct spscring rxring
The ring buffer used to control the receive queue.
unsigned rxbuf_posted
A flag indicating whether rxbuf_task has been posted to exec.
int result
The result of the read operation: 1 if a CAN frame is received, 0 if an error frame is received,...
int errc
The error number, obtained as if by get_errc(), if result is -1.
A CAN channel read operation.
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the read operation.
struct io_can_chan_read_result r
The result of the read operation.
struct timespec * tp
The address at which to store the system time at which the CAN frame or CAN error frame was received.
struct can_msg * msg
The address at which to store the CAN frame.
struct can_err * err
The address at which to store the CAN error frame.
A CAN channel write operation.
const struct can_msg * msg
A pointer to the CAN frame to be written.
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the write operation.
int errc
The error number, obtained as if by get_errc(), if an error occurred or the operation was canceled.
An object representing a file descriptor being monitored for I/O events.
The virtual table of an I/O service.
A node in a singly-linked list.
struct slnode * next
A pointer to the next node in the list.
A single-producer, single-consumer ring buffer.
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.
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.
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
size_t ev_task_queue_post(struct sllist *queue)
Post the tasks in queue to their respective executors and invokes ev_exec_on_task_fini() for each of ...
This header file is part of the C11 and POSIX compatibility library; it includes <unistd....
This header file is part of the utilities library; it contains the time function declarations.