2 * LiZaRd -- Fast compression method based on Lempel-Ziv 77
4 * (c) 2004, Robert Spalek <robert@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
11 #include <ucw/threads.h>
12 #include <ucw/sighandler.h>
13 #include <ucw/lizard.h>
21 struct lizard_buffer {
26 struct lizard_buffer *
29 struct lizard_buffer *buf = xmalloc(sizeof(struct lizard_buffer));
32 handle_signal(SIGSEGV);
37 lizard_free(struct lizard_buffer *buf)
39 unhandle_signal(SIGSEGV);
41 munmap(buf->ptr, buf->len + CPU_PAGE_SIZE);
46 lizard_realloc(struct lizard_buffer *buf, uns max_len)
47 /* max_len needs to be aligned to CPU_PAGE_SIZE */
49 if (max_len <= buf->len)
51 if (max_len < 2*buf->len) // to ensure logarithmic cost
55 munmap(buf->ptr, buf->len + CPU_PAGE_SIZE);
57 buf->ptr = mmap(NULL, buf->len + CPU_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
58 if (buf->ptr == MAP_FAILED)
59 die("mmap(anonymous, %d bytes): %m", (uns)(buf->len + CPU_PAGE_SIZE));
60 if (mprotect(buf->ptr + buf->len, CPU_PAGE_SIZE, PROT_NONE) < 0)
64 static jmp_buf safe_decompress_jump;
66 sigsegv_handler(int signal UNUSED)
68 longjmp(safe_decompress_jump, 1);
73 lizard_decompress_safe(const byte *in, struct lizard_buffer *buf, uns expected_length)
75 uns lock_offset = ALIGN_TO(expected_length + 3, CPU_PAGE_SIZE); // +3 due to the unaligned access
76 if (lock_offset > buf->len)
77 lizard_realloc(buf, lock_offset);
78 volatile ucw_sighandler_t old_handler = set_signal_handler(SIGSEGV, sigsegv_handler);
80 if (!setjmp(safe_decompress_jump))
82 ptr = buf->ptr + buf->len - lock_offset;
83 int len = lizard_decompress(in, ptr);
84 if (len != (int) expected_length)
92 msg(L_ERROR, "SIGSEGV caught in lizard_decompress()");
96 set_signal_handler(SIGSEGV, old_handler);