pipadoc uses some bashisms
[nobug.git] / src / nobug_ringbuffer.c
bloba1a6a1531dddc990121f0210df6751180159ea4b
1 /*
2 This file is part of the NoBug debugging library.
4 Copyright (C) 2007, 2008, Christian Thaeter <chth@gmx.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, contact Christian Thaeter <ct@pipapo.org>.
19 #include <fcntl.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <stdlib.h>
24 #include <sys/mman.h>
26 #define NOBUG_LIBNOBUG_C
27 #include "nobug.h"
29 #define NOBUG_RINGBUFFER_MAX_MSG 4094
31 struct nobug_ringbuffer*
32 nobug_ringbuffer_init (struct nobug_ringbuffer* self, size_t size, const char * name, int flags)
34 size_t pagesz = sysconf (_SC_PAGESIZE);
36 size = (size + pagesz-1) & ~(pagesz-1);
37 self->maxmsg = (NOBUG_RINGBUFFER_MAX_MSG+2 + pagesz-1) & ~(pagesz-1);
39 self->name[255] = '\0';
40 if (!name)
42 strcpy(self->name, "/tmp/nobug_ringbufferXXXXXX");
44 else
46 strncpy(self->name, name, 255);
49 int fd = mkstemp(self->name);
51 int oflags = O_RDWR|O_CREAT;
52 if (!(flags & NOBUG_RINGBUFFER_APPEND))
53 oflags |= O_TRUNC;
55 if (fd == -1 && errno == EINVAL)
56 fd = open(self->name, oflags, 0600);
58 if (fd == -1)
60 /* still error, exit here */
61 fprintf(stderr, "nobug_ringbuffer: Failed to open nobug_ringbuffer %s: %s\n", self->name, strerror(errno));
62 exit (EXIT_FAILURE);
65 if (!name || flags & NOBUG_RINGBUFFER_TEMP)
66 unlink (self->name);
68 if (!name || !(flags & NOBUG_RINGBUFFER_KEEP))
70 /* just in case we need the name later, store the first character at the end */
71 self->name[255] = self->name[0];
72 self->name[0] = 0;
75 if (ftruncate(fd, size))
77 fprintf(stderr, "nobug_ringbuffer: Failed to truncate ringbuffer to %zd: %s\n",
78 size, strerror(errno));
79 exit (EXIT_FAILURE);
81 self->size = size;
83 /* get contigous address range */
84 char * start = mmap (0, size+2*self->maxmsg, PROT_NONE, MAP_SHARED|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);
85 if (!start)
87 fprintf(stderr, "nobug_ringbuffer: Failed to reserve %zd bytes of address space: %s\n",
88 size+2*self->maxmsg, strerror(errno));
89 exit (EXIT_FAILURE);
92 /* map the backing file */
93 self->start = mmap (start+self->maxmsg, size, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, 0);
94 if (!self->start)
96 fprintf(stderr, "nobug_ringbuffer: Failed to mmap backing file, %s\n", strerror(errno));
97 exit (EXIT_FAILURE);
99 /* map beginning after the end */
100 if (!mmap (start+self->maxmsg+size, self->maxmsg, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, 0))
102 fprintf(stderr, "nobug_ringbuffer: Failed to mmap trailing guard page, %s\n", strerror(errno));
103 exit (EXIT_FAILURE);
105 /* map end before beginning */
106 if (!mmap (start, self->maxmsg, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, size-self->maxmsg))
108 fprintf(stderr, "nobug_ringbuffer: Failed to mmap leading guard page, %s\n", strerror(errno));
109 exit (EXIT_FAILURE);
112 close (fd);
114 if (flags & NOBUG_RINGBUFFER_APPEND)
116 start = memchr (self->start, ~0, size);
117 if (!start)
118 /* new file, can't append */
119 goto init;
120 self->pos = start-1;
121 if (self->pos < self->start)
122 self->pos += size;
124 else
126 init:
127 /* set pos to the end of the file, then new writes will start at the beginning */
128 self->pos = self->start+size-1;
129 /* ~0 is used as marker for the turnaround point */
130 self->pos[1] = ~0;
132 return self;
136 struct nobug_ringbuffer*
137 nobug_ringbuffer_new (size_t size, const char * name, int flags)
139 struct nobug_ringbuffer* self = malloc (sizeof (struct nobug_ringbuffer));
140 if (!self)
141 return NULL;
142 return nobug_ringbuffer_init (self, size, name, flags);
146 struct nobug_ringbuffer*
147 nobug_ringbuffer_destroy (struct nobug_ringbuffer* self)
149 if (self->name[0])
150 unlink(self->name);
151 munmap(self->start-self->maxmsg, self->size + 2 * self->maxmsg);
152 return self;
156 void
157 nobug_ringbuffer_delete (struct nobug_ringbuffer* self)
159 free (nobug_ringbuffer_destroy (self));
164 nobug_ringbuffer_vprintf (struct nobug_ringbuffer* self, const char* fmt, va_list ap)
166 int written = vsnprintf (self->pos + 1, self->maxmsg-2, fmt, ap);
167 self->pos += (written + 1);
169 if (self->pos > self->start+self->size)
170 self->pos -= self->size;
172 self->pos[1] = ~0;
174 return written;
179 nobug_ringbuffer_printf (struct nobug_ringbuffer* self, const char* fmt, ...)
181 va_list ap;
182 va_start (ap, fmt);
183 int written = nobug_ringbuffer_vprintf (self, fmt, ap);
184 va_end(ap);
185 return written;
189 char*
190 nobug_ringbuffer_prev (struct nobug_ringbuffer* self, char* pos)
192 if (!pos)
193 pos = self->pos;
194 else
195 --pos;
197 while(!*--pos);
198 while(*--pos);
199 if (pos < self->start)
200 pos += self->size;
202 if (pos[1] == ~0)
203 return NULL;
205 return pos+1;
208 char*
209 nobug_ringbuffer_next (struct nobug_ringbuffer* self, char* pos)
211 if (!pos)
212 pos = self->pos+1;
214 while (*++pos);
215 while (!*++pos);
216 if (pos > self->start+self->size)
217 pos -= self->size;
219 if (*pos == ~0)
220 return NULL;
222 return pos;
226 nobug_ringbuffer_save (struct nobug_ringbuffer* self, FILE* out)
228 int ret = 0;
229 int cnt;
230 char* next;
232 for (next = nobug_ringbuffer_next (self, NULL); next; next = nobug_ringbuffer_next(self, next))
234 cnt = fprintf (out,"%s\n", next);
235 if (cnt < 0)
236 return -ret-1;
237 else
238 ret += cnt;
240 return ret;
244 nobug_ringbuffer_load (struct nobug_ringbuffer* self, FILE* in)
246 int ret = 0;
247 char buf[NOBUG_RINGBUFFER_MAX_MSG];
249 while (fgets(buf, self->maxmsg, in))
251 size_t l = strlen(buf);
252 if (buf[l-1] == '\n')
253 buf[l-1] = '\0';
254 ret += nobug_ringbuffer_printf (self, "%s", buf);
256 return ret;
259 char*
260 nobug_ringbuffer_pos (struct nobug_ringbuffer* self)
262 return self->pos+1;
265 void
266 nobug_ringbuffer_pop (struct nobug_ringbuffer* self)
268 self->pos[0] = '\n'; /* clear the \0 */
269 self->pos[1] = ' '; /* clear the ~0 */
271 self->pos = strrchr(self->pos, 0);
272 if (self->pos < self->start)
273 self->pos += self->size;
275 self->pos[1] = ~0;