Update copyright headers according to git blame output
[nobug.git] / src / nobug_ringbuffer.c
blob03bc8000b49d9b405f1d1d86ecaafd7ef35e3a94
1 /*
2 This file is part of the NoBug debugging library.
4 Copyright (C)
5 2007, 2008, 2009, 2010, Christian Thaeter <ct@pipapo.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, contact Christian Thaeter <ct@pipapo.org>.
20 #include <fcntl.h>
21 #include <errno.h>
22 #include <unistd.h>
23 #include <stdlib.h>
25 #include <sys/mman.h>
27 #define NOBUG_LIBNOBUG_C
28 #include "nobug.h"
30 #define NOBUG_RINGBUFFER_MAX_MSG 4094
32 #include "llist.h"
34 #if NOBUG_USE_PTHREAD
35 pthread_mutex_t nobug_ringbuffer_mutex = PTHREAD_MUTEX_INITIALIZER;
36 #endif
37 LLIST_AUTO(nobug_ringbuffer_registry);
40 struct nobug_ringbuffer*
41 nobug_ringbuffer_init (struct nobug_ringbuffer* self, size_t size, const char * name, int flags)
43 size_t pagesz = sysconf (_SC_PAGESIZE);
45 size = (size + pagesz-1) & ~(pagesz-1);
46 self->maxmsg = (NOBUG_RINGBUFFER_MAX_MSG+2 + pagesz-1) & ~(pagesz-1);
48 self->name[255] = '\0';
49 if (!name)
51 strcpy(self->name, "/tmp/nobug_ringbufferXXXXXX");
53 else
55 strncpy(self->name, name, 255);
58 int fd = mkstemp(self->name);
60 int oflags = O_RDWR|O_CREAT;
61 if (!(flags & NOBUG_RINGBUFFER_APPEND))
62 oflags |= O_TRUNC;
64 if (fd == -1 && errno == EINVAL)
65 fd = open(self->name, oflags, 0600);
67 if (fd == -1)
69 /* still error, exit here */
70 fprintf(stderr, "nobug_ringbuffer: Failed to open nobug_ringbuffer %s: %s\n", self->name, strerror(errno));
71 exit (EXIT_FAILURE);
74 if (!name || flags & NOBUG_RINGBUFFER_TEMP)
75 unlink (self->name);
77 if (!name || !(flags & NOBUG_RINGBUFFER_KEEP))
79 /* just in case we need the name later, store the first character at the end */
80 self->name[255] = self->name[0];
81 self->name[0] = 0;
84 if (ftruncate(fd, size))
86 fprintf(stderr, "nobug_ringbuffer: Failed to truncate ringbuffer to %zd: %s\n",
87 size, strerror(errno));
88 exit (EXIT_FAILURE);
90 self->size = size;
92 /* get contigous address range */
93 char * start = mmap (0, size+2*self->maxmsg, PROT_NONE, MAP_SHARED|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);
94 if (!start)
96 fprintf(stderr, "nobug_ringbuffer: Failed to reserve %zd bytes of address space: %s\n",
97 size+2*self->maxmsg, strerror(errno));
98 exit (EXIT_FAILURE);
101 /* map the backing file */
102 self->start = mmap (start+self->maxmsg, size, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, 0);
103 if (!self->start)
105 fprintf(stderr, "nobug_ringbuffer: Failed to mmap backing file, %s\n", strerror(errno));
106 exit (EXIT_FAILURE);
108 /* map beginning after the end */
109 if (!mmap (start+self->maxmsg+size, self->maxmsg, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, 0))
111 fprintf(stderr, "nobug_ringbuffer: Failed to mmap trailing guard page, %s\n", strerror(errno));
112 exit (EXIT_FAILURE);
114 /* map end before beginning */
115 if (!mmap (start, self->maxmsg, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, size-self->maxmsg))
117 fprintf(stderr, "nobug_ringbuffer: Failed to mmap leading guard page, %s\n", strerror(errno));
118 exit (EXIT_FAILURE);
121 close (fd);
123 if (flags & NOBUG_RINGBUFFER_APPEND)
125 start = memchr (self->start, ~0, size);
126 if (!start)
127 /* new file, can't append */
128 goto init;
129 self->pos = start-1;
130 if (self->pos < self->start)
131 self->pos += size;
133 else
135 init:
136 /* set pos to the end of the file, then new writes will start at the beginning */
137 self->pos = self->start+size-1;
138 /* ~0 is used as marker for the turnaround point */
139 self->pos[1] = ~0;
142 #if NOBUG_USE_PTHREAD
143 pthread_mutex_lock (&nobug_ringbuffer_mutex);
144 llist_insert_tail (&nobug_ringbuffer_registry, llist_init (&self->node));
145 pthread_mutex_unlock (&nobug_ringbuffer_mutex);
146 #else
147 llist_insert_tail (&nobug_ringbuffer_registry, llist_init (&self->node));
148 #endif
150 return self;
154 struct nobug_ringbuffer*
155 nobug_ringbuffer_new (size_t size, const char * name, int flags)
157 struct nobug_ringbuffer* self = malloc (sizeof (struct nobug_ringbuffer));
158 if (!self)
159 return NULL;
160 return nobug_ringbuffer_init (self, size, name, flags);
164 struct nobug_ringbuffer*
165 nobug_ringbuffer_destroy (struct nobug_ringbuffer* self)
167 #if NOBUG_USE_PTHREAD
168 pthread_mutex_lock (&nobug_ringbuffer_mutex);
169 llist_unlink (&self->node);
170 pthread_mutex_unlock (&nobug_ringbuffer_mutex);
171 #else
172 llist_unlink (&self->node);
173 #endif
175 if (self->name[0])
176 unlink(self->name);
177 munmap(self->start-self->maxmsg, self->size + 2 * self->maxmsg);
178 return self;
182 void
183 nobug_ringbuffer_delete (struct nobug_ringbuffer* self)
185 free (nobug_ringbuffer_destroy (self));
189 void
190 nobug_ringbuffer_sync (struct nobug_ringbuffer* self)
192 msync (self->start, self->size, MS_SYNC);
196 void
197 nobug_ringbuffer_allsync (void)
199 #if NOBUG_USE_PTHREAD
200 pthread_mutex_lock (&nobug_ringbuffer_mutex);
201 LLIST_FOREACH(&nobug_ringbuffer_registry, n)
202 nobug_ringbuffer_sync ((struct nobug_ringbuffer*) n);
203 pthread_mutex_unlock (&nobug_ringbuffer_mutex);
204 #else
205 LLIST_FOREACH(&nobug_ringbuffer_registry, n)
206 nobug_ringbuffer_sync ((struct nobug_ringbuffer*) n);
207 #endif
212 nobug_ringbuffer_vprintf (struct nobug_ringbuffer* self, const char* fmt, va_list ap)
214 int written = vsnprintf (self->pos + 1, self->maxmsg-2, fmt, ap);
215 self->pos += (written + 1);
217 if (self->pos > self->start+self->size)
218 self->pos -= self->size;
220 self->pos[1] = ~0;
222 return written;
227 nobug_ringbuffer_printf (struct nobug_ringbuffer* self, const char* fmt, ...)
229 va_list ap;
230 va_start (ap, fmt);
231 int written = nobug_ringbuffer_vprintf (self, fmt, ap);
232 va_end(ap);
233 return written;
237 char*
238 nobug_ringbuffer_append (struct nobug_ringbuffer* self)
240 if (self->pos[-1] != 0)
241 --self->pos;
243 return self->pos;
247 char*
248 nobug_ringbuffer_prev (struct nobug_ringbuffer* self, char* pos)
250 if (!pos)
251 pos = self->pos;
252 else
253 --pos;
255 while(!*--pos);
256 while(*--pos);
257 if (pos < self->start)
258 pos += self->size;
260 if (pos[1] == (char)~0)
261 return NULL;
263 return pos+1;
266 char*
267 nobug_ringbuffer_next (struct nobug_ringbuffer* self, char* pos)
269 if (!pos)
270 pos = self->pos+1;
272 while (*++pos);
273 while (!*++pos);
274 if (pos > self->start+self->size)
275 pos -= self->size;
277 if (*pos == (char)~0)
278 return NULL;
280 return pos;
284 nobug_ringbuffer_save (struct nobug_ringbuffer* self, FILE* out)
286 int ret = 0;
287 int cnt;
288 char* next;
290 for (next = nobug_ringbuffer_next (self, NULL); next; next = nobug_ringbuffer_next(self, next))
292 cnt = fprintf (out,"%s\n", next);
293 if (cnt < 0)
294 return -ret-1;
295 else
296 ret += cnt;
298 return ret;
302 nobug_ringbuffer_load (struct nobug_ringbuffer* self, FILE* in)
304 int ret = 0;
305 char buf[NOBUG_RINGBUFFER_MAX_MSG];
307 while (fgets(buf, self->maxmsg, in))
309 size_t l = strlen(buf);
310 if (buf[l-1] == '\n')
311 buf[l-1] = '\0';
312 ret += nobug_ringbuffer_printf (self, "%s", buf);
314 return ret;
317 char*
318 nobug_ringbuffer_pos (struct nobug_ringbuffer* self)
320 return self->pos+1;
323 void
324 nobug_ringbuffer_pop (struct nobug_ringbuffer* self)
326 self->pos[0] = '\n'; /* clear the \0 */
327 self->pos[1] = ' '; /* clear the ~0 */
329 self->pos = strrchr(self->pos, 0);
330 if (self->pos < self->start)
331 self->pos += self->size;
333 self->pos[1] = ~0;