diff options
Diffstat (limited to 'lib/intel_allocator_msgchannel.c')
-rw-r--r-- | lib/intel_allocator_msgchannel.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/lib/intel_allocator_msgchannel.c b/lib/intel_allocator_msgchannel.c new file mode 100644 index 00000000..8280bc4e --- /dev/null +++ b/lib/intel_allocator_msgchannel.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/msg.h> +#include <sys/stat.h> +#include <fcntl.h> +#include "igt.h" +#include "intel_allocator_msgchannel.h" + +extern __thread pid_t child_tid; + +/* ----- SYSVIPC MSGQUEUE ----- */ + +#define FTOK_IGT_ALLOCATOR_KEY "/tmp/igt.allocator.key" +#define FTOK_IGT_ALLOCATOR_PROJID 2020 + +#define ALLOCATOR_REQUEST 1 + +struct msgqueue_data { + key_t key; + int queue; +}; + +struct msgqueue_buf { + long mtype; + union { + struct alloc_req request; + struct alloc_resp response; + } data; +}; + +static void msgqueue_init(struct msg_channel *channel) +{ + struct msgqueue_data *msgdata; + struct msqid_ds qstat; + key_t key; + int fd, queue; + + igt_debug("Init msgqueue\n"); + + /* Create ftok key only if not exists */ + fd = open(FTOK_IGT_ALLOCATOR_KEY, O_CREAT | O_EXCL | O_WRONLY, 0600); + igt_assert(fd >= 0 || errno == EEXIST); + if (fd >= 0) + close(fd); + + key = ftok(FTOK_IGT_ALLOCATOR_KEY, FTOK_IGT_ALLOCATOR_PROJID); + igt_assert(key != -1); + igt_debug("Queue key: %x\n", (int) key); + + queue = msgget(key, 0); + if (queue != -1) { + igt_assert(msgctl(queue, IPC_STAT, &qstat) == 0); + igt_debug("old messages: %lu\n", qstat.msg_qnum); + igt_assert(msgctl(queue, IPC_RMID, NULL) == 0); + } + + queue = msgget(key, IPC_CREAT); + igt_debug("msg queue: %d\n", queue); + + msgdata = calloc(1, sizeof(*msgdata)); + igt_assert(msgdata); + msgdata->key = key; + msgdata->queue = queue; + channel->priv = msgdata; +} + +static void msgqueue_deinit(struct msg_channel *channel) +{ + struct msgqueue_data *msgdata = channel->priv; + + igt_debug("Deinit msgqueue\n"); + msgctl(msgdata->queue, IPC_RMID, NULL); + free(channel->priv); +} + +static int msgqueue_send_req(struct msg_channel *channel, + struct alloc_req *request) +{ + struct msgqueue_data *msgdata = channel->priv; + struct msgqueue_buf buf = {0}; + int ret; + + buf.mtype = ALLOCATOR_REQUEST; + buf.data.request.request_type = 1; + memcpy(&buf.data.request, request, sizeof(*request)); + +retry: + ret = msgsnd(msgdata->queue, &buf, sizeof(buf) - sizeof(long), 0); + if (ret == -1 && errno == EINTR) + goto retry; + + if (ret == -1) + igt_warn("Error: %s\n", strerror(errno)); + + return ret; +} + +static int msgqueue_recv_req(struct msg_channel *channel, + struct alloc_req *request) +{ + struct msgqueue_data *msgdata = channel->priv; + struct msgqueue_buf buf = {0}; + int ret, size = sizeof(buf) - sizeof(long); + +retry: + ret = msgrcv(msgdata->queue, &buf, size, ALLOCATOR_REQUEST, 0); + if (ret == -1 && errno == EINTR) + goto retry; + + if (ret == size) + memcpy(request, &buf.data.request, sizeof(*request)); + else if (ret == -1) + igt_warn("Error: %s\n", strerror(errno)); + + return ret; +} + +static int msgqueue_send_resp(struct msg_channel *channel, + struct alloc_resp *response) +{ + struct msgqueue_data *msgdata = channel->priv; + struct msgqueue_buf buf = {0}; + int ret; + + buf.mtype = response->tid; + memcpy(&buf.data.response, response, sizeof(*response)); + +retry: + ret = msgsnd(msgdata->queue, &buf, sizeof(buf) - sizeof(long), 0); + if (ret == -1 && errno == EINTR) + goto retry; + + if (ret == -1) + igt_warn("Error: %s\n", strerror(errno)); + + return ret; +} + +static int msgqueue_recv_resp(struct msg_channel *channel, + struct alloc_resp *response) +{ + struct msgqueue_data *msgdata = channel->priv; + struct msgqueue_buf buf = {0}; + int ret, size = sizeof(buf) - sizeof(long); + +retry: + ret = msgrcv(msgdata->queue, &buf, sizeof(buf) - sizeof(long), + response->tid, 0); + if (ret == -1 && errno == EINTR) + goto retry; + + if (ret == size) + memcpy(response, &buf.data.response, sizeof(*response)); + else if (ret == -1) + igt_warn("Error: %s\n", strerror(errno)); + + return ret; +} + +static struct msg_channel msgqueue_channel = { + .priv = NULL, + .init = msgqueue_init, + .deinit = msgqueue_deinit, + .send_req = msgqueue_send_req, + .recv_req = msgqueue_recv_req, + .send_resp = msgqueue_send_resp, + .recv_resp = msgqueue_recv_resp, +}; + +struct msg_channel *intel_allocator_get_msgchannel(enum msg_channel_type type) +{ + struct msg_channel *channel = NULL; + + switch (type) { + case CHANNEL_SYSVIPC_MSGQUEUE: + channel = &msgqueue_channel; + } + + igt_assert(channel); + + return channel; +} |