Index: gc.c =================================================================== --- gc.c (revision 34318) +++ gc.c (working copy) @@ -36,6 +36,9 @@ #if defined _WIN32 || defined __CYGWIN__ #include +#elif defined(__OpenBSD__) +/* workaround for OpenBSD broken posix_memalign() */ +#include #elif defined(HAVE_POSIX_MEMALIGN) #elif defined(HAVE_MEMALIGN) #include @@ -1083,6 +1086,11 @@ } } +#if defined(__OpenBSD__) +/* workaround for OpenBSD broken posix_memalign() */ +static st_table *am_size_table = NULL; +#endif + static void * aligned_malloc(size_t alignment, size_t size) { @@ -1092,6 +1100,43 @@ res = __mingw_aligned_malloc(size, alignment); #elif _WIN32 || defined __CYGWIN__ res = _aligned_malloc(size, alignment); +#elif defined(__OpenBSD__) + /* OpenBSD posix_memalign() is broken. Quoting BUGS in manual: + * "Only alignments up to the page size can be specified." + * This workaround assumes that + * 1. Ruby wants large alignment and large size. + * 2. OpenBSD mmap() tends to return random addresses. + * 3. OpenBSD mmap() tends to obey address hints. */ + { + size_t mask; + int tries; + void *target; + + mask = alignment - 1; + if (alignment & mask) + return NULL; /* alignment is not power of 2 */ + tries = 10; + while (tries--) { + /* find a random place in memory */ + target = mmap(NULL, 1, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0); + if (target == NULL) + return NULL; + munmap(target, 1); + /* align target */ + target = (void *)((size_t)target & ~mask); + res = mmap(target, size, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0); + if (res == target) { + /* success! */ + if (!am_size_table) + am_size_table = st_init_numtable(); + st_insert(am_size_table, (st_data_t)res, size); + return res; + } + if (res != MAP_FAILED) + munmap(res, size); + } + return NULL; /* no more tries */ + } #elif defined(HAVE_POSIX_MEMALIGN) if (posix_memalign(&res, alignment, size) == 0) { return res; @@ -1113,6 +1158,14 @@ __mingw_aligned_free(ptr); #elif _WIN32 || defined __CYGWIN__ _aligned_free(ptr); +#elif defined(__OpenBSD__) + /* workaround for OpenBSD broken posix_memalign() */ + { + st_data_t res, val; + res = (st_data_t)ptr; + if (am_size_table && st_delete(am_size_table, &res, &val)) + munmap(ptr, (size_t)val); + } #else free(ptr); #endif