some cosmetics
[nobug.git] / src / nobug_ringbuffer.c
blob1239f59cab068ebbc48dcf2999227b56e9f01e85
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 ftruncate(fd, size);
76 self->size = size;
78 /* get contigous address range */
79 char * start = mmap (0, size+2*self->maxmsg, PROT_NONE, MAP_SHARED|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);
80 if (!start)
82 fprintf(stderr, "nobug_ringbuffer: Failed to reserve %d bytes of address space: %s\n",
83 size+2*self->maxmsg, strerror(errno));
84 exit (EXIT_FAILURE);
87 /* map the backing file */
88 self->start = mmap (start+self->maxmsg, size, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, 0);
89 if (!self->start)
91 fprintf(stderr, "nobug_ringbuffer: Failed to mmap backing file, %s\n", strerror(errno));
92 exit (EXIT_FAILURE);
94 /* map beginning after the end */
95 if (!mmap (start+self->maxmsg+size, self->maxmsg, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, 0))
97 fprintf(stderr, "nobug_ringbuffer: Failed to mmap trailing guard page, %s\n", strerror(errno));
98 exit (EXIT_FAILURE);
100 /* map end before beginning */
101 if (!mmap (start, self->maxmsg, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, size-self->maxmsg))
103 fprintf(stderr, "nobug_ringbuffer: Failed to mmap leading guard page, %s\n", strerror(errno));
104 exit (EXIT_FAILURE);
107 close (fd);
109 if (flags & NOBUG_RINGBUFFER_APPEND)
111 start = memchr (self->start, ~0, size);
112 if (!start)
113 /* new file, can't append */
114 goto init;
115 self->pos = start-1;
116 if (self->pos < self->start)
117 self->pos += size;
119 else
121 init:
122 /* set pos to the end of the file, then new writes will start at the beginning */
123 self->pos = self->start+size-1;
124 /* ~0 is used as marker for the turnaround point */
125 self->pos[1] = ~0;
127 return self;
131 struct nobug_ringbuffer*
132 nobug_ringbuffer_new (size_t size, const char * name, int flags)
134 struct nobug_ringbuffer* self = malloc (sizeof (struct nobug_ringbuffer));
135 if (!self)
136 return NULL;
137 return nobug_ringbuffer_init (self, size, name, flags);
141 struct nobug_ringbuffer*
142 nobug_ringbuffer_destroy (struct nobug_ringbuffer* self)
144 if (self->name[0])
145 unlink(self->name);
146 munmap(self->start-self->maxmsg, self->size + 2 * self->maxmsg);
147 return self;
151 void
152 nobug_ringbuffer_delete (struct nobug_ringbuffer* self)
154 free (nobug_ringbuffer_destroy (self));
159 nobug_ringbuffer_vprintf (struct nobug_ringbuffer* self, const char* fmt, va_list ap)
161 int written = vsnprintf (self->pos + 1, self->maxmsg-2, fmt, ap);
162 self->pos += (written + 1);
164 if (self->pos > self->start+self->size)
165 self->pos -= self->size;
167 self->pos[1] = ~0;
169 return written;
174 nobug_ringbuffer_printf (struct nobug_ringbuffer* self, const char* fmt, ...)
176 va_list ap;
177 va_start (ap, fmt);
178 int written = nobug_ringbuffer_vprintf (self, fmt, ap);
179 va_end(ap);
180 return written;
184 char*
185 nobug_ringbuffer_prev (struct nobug_ringbuffer* self, char* pos)
187 if (!pos)
188 pos = self->pos;
189 else
190 --pos;
192 while(!*--pos);
193 while(*--pos);
194 if (pos < self->start)
195 pos += self->size;
197 if (pos[1] == ~0)
198 return NULL;
200 return pos+1;
203 char*
204 nobug_ringbuffer_next (struct nobug_ringbuffer* self, char* pos)
206 if (!pos)
207 pos = self->pos+1;
209 while (*++pos);
210 while (!*++pos);
211 if (pos > self->start+self->size)
212 pos -= self->size;
214 if (*pos == ~0)
215 return NULL;
217 return pos;
221 nobug_ringbuffer_save (struct nobug_ringbuffer* self, FILE* out)
223 int ret = 0;
224 int cnt;
225 char* next;
227 for (next = nobug_ringbuffer_next (self, NULL); next; next = nobug_ringbuffer_next(self, next))
229 cnt = fprintf (out,"%s\n", next);
230 if (cnt < 0)
231 return -ret-1;
232 else
233 ret += cnt;
235 return ret;
239 nobug_ringbuffer_load (struct nobug_ringbuffer* self, FILE* in)
241 int ret = 0;
242 char buf[NOBUG_RINGBUFFER_MAX_MSG];
244 while (fgets(buf, self->maxmsg, in))
246 size_t l = strlen(buf);
247 if (buf[l-1] == '\n')
248 buf[l-1] = '\0';
249 ret += nobug_ringbuffer_printf (self, "%s", buf);
251 return ret;
254 char*
255 nobug_ringbuffer_pos (struct nobug_ringbuffer* self)
257 return self->pos+1;
260 void
261 nobug_ringbuffer_pop (struct nobug_ringbuffer* self)
263 self->pos[0] = '\n'; /* clear the \0 */
264 self->pos[1] = ' '; /* clear the ~0 */
266 self->pos = strrchr(self->pos, 0);
267 if (self->pos < self->start)
268 self->pos += self->size;
270 self->pos[1] = ~0;