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>.
26 #define NOBUG_LIBNOBUG_C
29 #define NOBUG_RINGBUFFER_MAX_MSG 4094
34 pthread_mutex_t nobug_ringbuffer_mutex
= PTHREAD_MUTEX_INITIALIZER
;
36 LLIST_AUTO(nobug_ringbuffer_registry
);
39 struct nobug_ringbuffer
*
40 nobug_ringbuffer_init (struct nobug_ringbuffer
* self
, size_t size
, const char * name
, int flags
)
42 size_t pagesz
= sysconf (_SC_PAGESIZE
);
44 size
= (size
+ pagesz
-1) & ~(pagesz
-1);
45 self
->maxmsg
= (NOBUG_RINGBUFFER_MAX_MSG
+2 + pagesz
-1) & ~(pagesz
-1);
47 self
->name
[255] = '\0';
50 strcpy(self
->name
, "/tmp/nobug_ringbufferXXXXXX");
54 strncpy(self
->name
, name
, 255);
57 int fd
= mkstemp(self
->name
);
59 int oflags
= O_RDWR
|O_CREAT
;
60 if (!(flags
& NOBUG_RINGBUFFER_APPEND
))
63 if (fd
== -1 && errno
== EINVAL
)
64 fd
= open(self
->name
, oflags
, 0600);
68 /* still error, exit here */
69 fprintf(stderr
, "nobug_ringbuffer: Failed to open nobug_ringbuffer %s: %s\n", self
->name
, strerror(errno
));
73 if (!name
|| flags
& NOBUG_RINGBUFFER_TEMP
)
76 if (!name
|| !(flags
& NOBUG_RINGBUFFER_KEEP
))
78 /* just in case we need the name later, store the first character at the end */
79 self
->name
[255] = self
->name
[0];
83 if (ftruncate(fd
, size
))
85 fprintf(stderr
, "nobug_ringbuffer: Failed to truncate ringbuffer to %zd: %s\n",
86 size
, strerror(errno
));
91 /* get contigous address range */
92 char * start
= mmap (0, size
+2*self
->maxmsg
, PROT_NONE
, MAP_SHARED
|MAP_ANONYMOUS
|MAP_NORESERVE
, -1, 0);
95 fprintf(stderr
, "nobug_ringbuffer: Failed to reserve %zd bytes of address space: %s\n",
96 size
+2*self
->maxmsg
, strerror(errno
));
100 /* map the backing file */
101 self
->start
= mmap (start
+self
->maxmsg
, size
, PROT_READ
|PROT_WRITE
, MAP_FIXED
|MAP_SHARED
, fd
, 0);
104 fprintf(stderr
, "nobug_ringbuffer: Failed to mmap backing file, %s\n", strerror(errno
));
107 /* map beginning after the end */
108 if (!mmap (start
+self
->maxmsg
+size
, self
->maxmsg
, PROT_READ
|PROT_WRITE
, MAP_FIXED
|MAP_SHARED
, fd
, 0))
110 fprintf(stderr
, "nobug_ringbuffer: Failed to mmap trailing guard page, %s\n", strerror(errno
));
113 /* map end before beginning */
114 if (!mmap (start
, self
->maxmsg
, PROT_READ
|PROT_WRITE
, MAP_FIXED
|MAP_SHARED
, fd
, size
-self
->maxmsg
))
116 fprintf(stderr
, "nobug_ringbuffer: Failed to mmap leading guard page, %s\n", strerror(errno
));
122 if (flags
& NOBUG_RINGBUFFER_APPEND
)
124 start
= memchr (self
->start
, ~0, size
);
126 /* new file, can't append */
129 if (self
->pos
< self
->start
)
135 /* set pos to the end of the file, then new writes will start at the beginning */
136 self
->pos
= self
->start
+size
-1;
137 /* ~0 is used as marker for the turnaround point */
141 #if NOBUG_USE_PTHREAD
142 pthread_mutex_lock (&nobug_ringbuffer_mutex
);
143 llist_insert_tail (&nobug_ringbuffer_registry
, llist_init (&self
->node
));
144 pthread_mutex_unlock (&nobug_ringbuffer_mutex
);
146 llist_insert_tail (&nobug_ringbuffer_registry
, llist_init (&self
->node
));
153 struct nobug_ringbuffer
*
154 nobug_ringbuffer_new (size_t size
, const char * name
, int flags
)
156 struct nobug_ringbuffer
* self
= malloc (sizeof (struct nobug_ringbuffer
));
159 return nobug_ringbuffer_init (self
, size
, name
, flags
);
163 struct nobug_ringbuffer
*
164 nobug_ringbuffer_destroy (struct nobug_ringbuffer
* self
)
166 #if NOBUG_USE_PTHREAD
167 pthread_mutex_lock (&nobug_ringbuffer_mutex
);
168 llist_unlink (&self
->node
);
169 pthread_mutex_unlock (&nobug_ringbuffer_mutex
);
171 llist_unlink (&self
->node
);
176 munmap(self
->start
-self
->maxmsg
, self
->size
+ 2 * self
->maxmsg
);
182 nobug_ringbuffer_delete (struct nobug_ringbuffer
* self
)
184 free (nobug_ringbuffer_destroy (self
));
189 nobug_ringbuffer_sync (struct nobug_ringbuffer
* self
)
191 msync (self
->start
, self
->size
, MS_SYNC
);
196 nobug_ringbuffer_allsync (void)
198 #if NOBUG_USE_PTHREAD
199 pthread_mutex_lock (&nobug_ringbuffer_mutex
);
200 LLIST_FOREACH(&nobug_ringbuffer_registry
, n
)
201 nobug_ringbuffer_sync ((struct nobug_ringbuffer
*) n
);
202 pthread_mutex_unlock (&nobug_ringbuffer_mutex
);
204 LLIST_FOREACH(&nobug_ringbuffer_registry
, n
)
205 nobug_ringbuffer_sync ((struct nobug_ringbuffer
*) n
);
211 nobug_ringbuffer_vprintf (struct nobug_ringbuffer
* self
, const char* fmt
, va_list ap
)
213 int written
= vsnprintf (self
->pos
+ 1, self
->maxmsg
-2, fmt
, ap
);
214 self
->pos
+= (written
+ 1);
216 if (self
->pos
> self
->start
+self
->size
)
217 self
->pos
-= self
->size
;
226 nobug_ringbuffer_printf (struct nobug_ringbuffer
* self
, const char* fmt
, ...)
230 int written
= nobug_ringbuffer_vprintf (self
, fmt
, ap
);
237 nobug_ringbuffer_append (struct nobug_ringbuffer
* self
)
239 if (self
->pos
[-1] != 0)
247 nobug_ringbuffer_prev (struct nobug_ringbuffer
* self
, char* pos
)
256 if (pos
< self
->start
)
259 if (pos
[1] == (char)~0)
266 nobug_ringbuffer_next (struct nobug_ringbuffer
* self
, char* pos
)
273 if (pos
> self
->start
+self
->size
)
276 if (*pos
== (char)~0)
283 nobug_ringbuffer_save (struct nobug_ringbuffer
* self
, FILE* out
)
289 for (next
= nobug_ringbuffer_next (self
, NULL
); next
; next
= nobug_ringbuffer_next(self
, next
))
291 cnt
= fprintf (out
,"%s\n", next
);
301 nobug_ringbuffer_load (struct nobug_ringbuffer
* self
, FILE* in
)
304 char buf
[NOBUG_RINGBUFFER_MAX_MSG
];
306 while (fgets(buf
, self
->maxmsg
, in
))
308 size_t l
= strlen(buf
);
309 if (buf
[l
-1] == '\n')
311 ret
+= nobug_ringbuffer_printf (self
, "%s", buf
);
317 nobug_ringbuffer_pos (struct nobug_ringbuffer
* self
)
323 nobug_ringbuffer_pop (struct nobug_ringbuffer
* self
)
325 self
->pos
[0] = '\n'; /* clear the \0 */
326 self
->pos
[1] = ' '; /* clear the ~0 */
328 self
->pos
= strrchr(self
->pos
, 0);
329 if (self
->pos
< self
->start
)
330 self
->pos
+= self
->size
;