]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/ringbuf.c
spelling: timeout
[mirror_lxc.git] / src / lxc / ringbuf.c
CommitLineData
f3d05ee6
CB
1/* liblxcapi
2 *
3 * Copyright © 2017 Christian Brauner <christian.brauner@ubuntu.com>.
4 * Copyright © 2017 Canonical Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
d38dd64a
CB
20#ifndef _GNU_SOURCE
21#define _GNU_SOURCE 1
22#endif
f3d05ee6
CB
23#define __STDC_FORMAT_MACROS
24#include <errno.h>
25#include <inttypes.h>
26#include <stdbool.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
f3d05ee6 30#include <sys/mman.h>
d38dd64a 31#include <unistd.h>
f3d05ee6 32
d38dd64a 33#include "config.h"
f3d05ee6 34#include "ringbuf.h"
6a886ddf 35#include "syscall_wrappers.h"
f3d05ee6
CB
36#include "utils.h"
37
38int lxc_ringbuf_create(struct lxc_ringbuf *buf, size_t size)
39{
40 char *tmp;
41 int ret;
42 int memfd = -1;
43
44 buf->size = size;
45 buf->r_off = 0;
46 buf->w_off = 0;
47
48 /* verify that we are at least given the multiple of a page size */
49 if (buf->size % lxc_getpagesize())
50 return -EINVAL;
51
52 buf->addr = mmap(NULL, buf->size * 2, PROT_NONE,
53 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
54 if (buf->addr == MAP_FAILED)
55 return -EINVAL;
56
57 memfd = memfd_create(".lxc_ringbuf", MFD_CLOEXEC);
58 if (memfd < 0) {
709384a0
CB
59 char template[] = P_tmpdir "/.lxc_ringbuf_XXXXXX";
60
f3d05ee6
CB
61 if (errno != ENOSYS)
62 goto on_error;
63
709384a0 64 memfd = lxc_make_tmpfile(template, true);
f3d05ee6
CB
65 }
66 if (memfd < 0)
67 goto on_error;
68
69 ret = ftruncate(memfd, buf->size);
70 if (ret < 0)
71 goto on_error;
72
73 tmp = mmap(buf->addr, buf->size, PROT_READ | PROT_WRITE,
74 MAP_FIXED | MAP_SHARED, memfd, 0);
75 if (tmp == MAP_FAILED || tmp != buf->addr)
76 goto on_error;
77
78 tmp = mmap(buf->addr + buf->size, buf->size, PROT_READ | PROT_WRITE,
79 MAP_FIXED | MAP_SHARED, memfd, 0);
80 if (tmp == MAP_FAILED || tmp != (buf->addr + buf->size))
81 goto on_error;
82
83 close(memfd);
84
85 return 0;
86
87on_error:
88 lxc_ringbuf_release(buf);
89 if (memfd >= 0)
90 close(memfd);
91 return -1;
92}
93
94void lxc_ringbuf_move_read_addr(struct lxc_ringbuf *buf, size_t len)
95{
96 buf->r_off += len;
97
98 if (buf->r_off < buf->size)
99 return;
100
101 /* wrap around */
102 buf->r_off -= buf->size;
103 buf->w_off -= buf->size;
104}
105
106/**
107 * lxc_ringbuf_write - write a message to the ringbuffer
108 * - The size of the message should never be greater than the size of the whole
109 * ringbuffer.
110 * - The write method will always succeed i.e. it will always advance the r_off
111 * if it detects that there's not enough space available to write the
112 * message.
113 */
114int lxc_ringbuf_write(struct lxc_ringbuf *buf, const char *msg, size_t len)
115{
116 char *w_addr;
117 uint64_t free;
118
119 /* sanity check: a write should never exceed the ringbuffer's total size */
120 if (len > buf->size)
121 return -EFBIG;
122
123 free = lxc_ringbuf_free(buf);
124
125 /* not enough space left so advance read address */
126 if (len > free)
127 lxc_ringbuf_move_read_addr(buf, len);
128 w_addr = lxc_ringbuf_get_write_addr(buf);
129 memcpy(w_addr, msg, len);
130 lxc_ringbuf_move_write_addr(buf, len);
131 return 0;
132}
133
134int lxc_ringbuf_read(struct lxc_ringbuf *buf, char *out, size_t *len)
135{
136 uint64_t used;
137
138 /* there's nothing to read */
139 if (buf->r_off == buf->w_off)
140 return -ENODATA;
141
142 /* read maximum amount available */
143 used = lxc_ringbuf_used(buf);
144 if (used < *len)
145 *len = used;
146
147 /* copy data to reader but don't advance addr */
148 memcpy(out, lxc_ringbuf_get_read_addr(buf), *len);
149 out[*len - 1] = '\0';
150 return 0;
151}