2 nobug_ringbuffer.c - a small debugging library
4 Copyright (C) 2007, Christian Thaeter <ct@pipapo.org>
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.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, contact me.
26 #define NOBUG_LIBNOBUG_C
29 #define NOBUG_RINGBUFFER_MAX_MSG 4094
32 nobug_ringbuffer_init (struct nobug_ringbuffer
* self
, size_t size
, const char * name
, enum nobug_ringbuffer_flags 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';
42 strcpy(self
->name
, "/tmp/nobug_ringbufferXXXXXX");
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
))
55 if (fd
== -1 && errno
== EINVAL
)
56 fd
= open(self
->name
, oflags
, 0600);
60 /* still error, exit here */
61 fprintf(stderr
, "nobug_ringbuffer: Failed to open nobug_ringbuffer %s: %s\n", self
->name
, strerror(errno
));
65 if (!name
|| flags
& NOBUG_RINGBUFFER_TEMP
)
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];
78 /* get contigous address range */
79 char * start
= mmap(0, size
+2*self
->maxmsg
, PROT_NONE
, MAP_SHARED
|MAP_ANONYMOUS
|MAP_NORESERVE
, -1, 0);
82 fprintf(stderr
, "nobug_ringbuffer: Failed to reserve %d bytes of address space: %s\n",
83 size
+2*self
->maxmsg
, strerror(errno
));
87 munmap(start
, size
+2*self
->maxmsg
);
89 /* map the backing file */
90 self
->start
= mmap(start
+self
->maxmsg
, size
, PROT_READ
|PROT_WRITE
, MAP_FIXED
|MAP_SHARED
, fd
, 0);
91 /* map beginning after the end */
92 mmap(start
+self
->maxmsg
+size
, self
->maxmsg
, PROT_READ
|PROT_WRITE
, MAP_FIXED
|MAP_SHARED
, fd
, 0);
93 /* map end before beginning */
94 mmap(start
, self
->maxmsg
, PROT_READ
|PROT_WRITE
, MAP_FIXED
|MAP_SHARED
, fd
, size
-self
->maxmsg
);
98 if (flags
& NOBUG_RINGBUFFER_APPEND
)
100 start
= memchr(self
->start
, ~0, size
);
102 /* new file, can't append */
105 if (self
->pos
< self
->start
)
111 /* set pos to the end of the file, then new writes will start at the beginning */
112 self
->pos
= self
->start
+size
-1;
113 /* ~0 is used as marker for the turnaround point */
119 nobug_ringbuffer_destroy (struct nobug_ringbuffer
* self
)
123 munmap(self
->start
-self
->maxmsg
, self
->size
+ 2 * self
->maxmsg
);
128 nobug_ringbuffer_printf (struct nobug_ringbuffer
* self
, const char* fmt
, ...)
132 int written
= vsnprintf (self
->pos
+ 1, self
->maxmsg
-2, fmt
, ap
);
134 self
->pos
+= (written
+ 1);
136 if (self
->pos
> self
->start
+self
->size
)
137 self
->pos
-= self
->size
;
145 nobug_ringbuffer_prev (struct nobug_ringbuffer
* self
, char* pos
)
154 if (pos
< self
->start
)
164 nobug_ringbuffer_next (struct nobug_ringbuffer
* self
, char* pos
)
171 if (pos
> self
->start
+self
->size
)
181 nobug_ringbuffer_save (struct nobug_ringbuffer
* self
, FILE* out
)
187 for (next
= nobug_ringbuffer_next(self
,NULL
); next
; next
= nobug_ringbuffer_next(self
, next
))
189 cnt
= fprintf (out
,"%s\n", next
);
199 nobug_ringbuffer_load (struct nobug_ringbuffer
* self
, FILE* in
)
202 char buf
[NOBUG_RINGBUFFER_MAX_MSG
];
204 while (fgets(buf
, self
->maxmsg
, in
))
206 size_t l
= strlen(buf
);
207 if (buf
[l
-1] == '\n')
209 ret
+= nobug_ringbuffer_printf (self
, "%s", buf
);
215 nobug_ringbuffer_pos (struct nobug_ringbuffer
* self
)
221 nobug_ringbuffer_pop (struct nobug_ringbuffer
* self
)
223 self
->pos
[0] = '\n'; /* clear the \0 */
224 self
->pos
[1] = ' '; /* clear the ~0 */
226 self
->pos
= strrchr(self
->pos
, 0);
227 if (self
->pos
< self
->start
)
228 self
->pos
+= self
->size
;