1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
// 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 MAXQLEN 4096
#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);
igt_assert(msgctl(queue, IPC_STAT, &qstat) == 0);
igt_debug("msg size in bytes: %lu\n", qstat.msg_qbytes);
qstat.msg_qbytes = MAXQLEN * sizeof(struct msgqueue_buf);
igt_debug("resizing queue to support %d requests\n", MAXQLEN);
igt_assert_f(msgctl(queue, IPC_SET, &qstat) == 0,
"Couldn't change queue size to %lu\n", qstat.msg_qbytes);
msgdata = calloc(1, sizeof(*msgdata));
igt_assert(msgdata);
msgdata->key = key;
msgdata->queue = queue;
channel->priv = msgdata;
channel->ready = true;
}
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);
channel->ready = false;
}
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;
}
|