/* * AVR emulator * Interprocess communication * * Copyright (C) 2007 Michael Buesch * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include "ipc.h" #include #include #include #define IPC_POLL_MAX_USECS 10000 int ipc_pipe_create(struct ipc_tx *tx, struct ipc_rx *rx) { int message_pipe[2]; int result_pipe[2]; int err; err = pipe(message_pipe); if (err) { perror("Create IPC message pipe"); return err; } err = pipe(result_pipe); if (err) { perror("Create IPC result pipe"); close(message_pipe[0]); close(message_pipe[1]); return err; } tx->message_pipe = message_pipe[1]; rx->message_pipe = message_pipe[0]; tx->result_pipe = result_pipe[0]; rx->result_pipe = result_pipe[1]; return 0; } void ipc_pipe_destroy_tx(struct ipc_tx *tx) { if (tx->message_pipe != -1) { close(tx->message_pipe); tx->message_pipe = -1; } if (tx->result_pipe != -1) { close(tx->result_pipe); tx->result_pipe = -1; } } void ipc_pipe_destroy_rx(struct ipc_rx *rx) { if (rx->message_pipe != -1) { close(rx->message_pipe); rx->message_pipe = -1; } if (rx->result_pipe != -1) { close(rx->result_pipe); rx->result_pipe = -1; } } void ipc_pipe_destroy(struct ipc_tx *tx, struct ipc_rx *rx) { ipc_pipe_destroy_tx(tx); ipc_pipe_destroy_rx(rx); } int ipc_dup2(struct ipc_tx *tx, int fd) { return dup2(tx->message_pipe, fd); } int ipc_message_send(struct ipc_tx *tx, const void *message, ipc_size_t msg_size, bool read_result) { ssize_t res; ipc_result_t result_code; res = write(tx->message_pipe, &msg_size, sizeof(msg_size)); if (unlikely(res != sizeof(msg_size))) return -EIO; res = write(tx->message_pipe, message, msg_size); if (unlikely(res != msg_size)) return -EIO; if (read_result) { res = read(tx->result_pipe, &result_code, sizeof(result_code)); if (unlikely(res != sizeof(result_code))) return -EIO; return result_code; } return 0; } int ipc_message_poll(struct ipc_rx *rx, void *message_buf, ipc_size_t buf_size) { ssize_t res; fd_set fdset; ipc_size_t msg_size; struct timeval tv = { .tv_sec = 0, .tv_usec = IPC_POLL_MAX_USECS, }; FD_ZERO(&fdset); FD_SET(rx->message_pipe, &fdset); res = select(FD_SETSIZE, &fdset, NULL, NULL, &tv); if (res <= 0) { /* Timeout. No data. */ return 0; } res = read(rx->message_pipe, &msg_size, sizeof(msg_size)); if (unlikely(res != sizeof(msg_size))) return -EIO; if (unlikely(msg_size > buf_size)) return -ENOBUFS; res = read(rx->message_pipe, message_buf, msg_size); if (unlikely(res != msg_size)) return -EIO; return msg_size; } int ipc_raw_line_poll(struct ipc_rx *rx, char *line_buf, size_t buf_size) { ssize_t res; fd_set fdset; struct timeval tv = { .tv_sec = 0, .tv_usec = IPC_POLL_MAX_USECS, }; size_t i; char c; FD_ZERO(&fdset); FD_SET(rx->message_pipe, &fdset); res = select(FD_SETSIZE, &fdset, NULL, NULL, &tv); if (res <= 0) { /* Timeout. No data. */ return 0; } for (i = 0; ; i++) { res = read(rx->message_pipe, &c, sizeof(c)); if (res != sizeof(c)) break; if (unlikely(i >= buf_size - 1)) return -ENOBUFS; line_buf[i] = c; if (c == '\n') { line_buf[i + 1] = '\0'; break; } } return i; } int ipc_send_result(struct ipc_rx *rx, ipc_result_t result_code) { ssize_t res; res = write(rx->result_pipe, &result_code, sizeof(result_code)); if (unlikely(res != sizeof(result_code))) return -EIO; return 0; } int ipc_payload_send(struct ipc_tx *tx, const void *buf, size_t size) { ssize_t res; ipc_result_t result_code; res = write(tx->message_pipe, buf, size); if (unlikely(res != size)) return -EIO; res = read(tx->result_pipe, &result_code, sizeof(result_code)); if (unlikely(res != sizeof(result_code))) return -EIO; return result_code; } int ipc_payload_receive(struct ipc_rx *rx, void *buf, size_t size) { ssize_t res; res = read(rx->message_pipe, buf, size); if (unlikely(res != size)) return -EIO; return 0; }