gl: clear w, h on reinit
[libpicofe.git] / linux / plat.c
index 660a095..2cdcace 100644 (file)
@@ -13,6 +13,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
+#include <stdint.h>
 #include <dirent.h>
 #include <sys/time.h>
 #include <time.h>
@@ -41,13 +42,27 @@ int plat_is_dir(const char *path)
        return 0;
 }
 
-static int plat_get_data_dir(char *dst, int len)
+int plat_get_data_dir(char *dst, int len)
+{
+       if (len > 1)
+               strcpy(dst, "/");
+       else    *dst = 0;
+       return strlen(dst);
+}
+
+static int plat_get_exe_dir(char *dst, int len)
 {
 #ifdef PICO_DATA_DIR
        memcpy(dst, PICO_DATA_DIR, sizeof PICO_DATA_DIR);
        return sizeof(PICO_DATA_DIR) - 1;
 #else
-       int j, ret = readlink("/proc/self/exe", dst, len - 1);
+       int j, ret = readlink(
+#ifdef __FreeBSD__
+       "/proc/curproc/file",
+#else
+       "/proc/self/exe",
+#endif
+       dst, len - 1);
        if (ret < 0) {
                perror("readlink");
                ret = 0;
@@ -65,9 +80,9 @@ static int plat_get_data_dir(char *dst, int len)
 
 int plat_get_skin_dir(char *dst, int len)
 {
-       int ret = plat_get_data_dir(dst, len);
+       int ret = plat_get_exe_dir(dst, len);
        if (ret < 0)
-               return ret;
+               ret = 0;
 
        memcpy(dst + ret, "skin/", sizeof "skin/");
        return ret + sizeof("skin/") - 1;
@@ -78,7 +93,7 @@ int plat_get_skin_dir(char *dst, int len)
 #endif
 int plat_get_root_dir(char *dst, int len)
 {
-#if !defined(__GP2X__) && !defined(PANDORA)
+#if !defined(NO_HOME_DIR) && !defined(__GP2X__) && !defined(PANDORA)
        const char *home = getenv("HOME");
        int ret;
 
@@ -90,7 +105,7 @@ int plat_get_root_dir(char *dst, int len)
                return ret;
        }
 #endif
-       return plat_get_data_dir(dst, len);
+       return plat_get_exe_dir(dst, len);
 }
 
 #ifdef __GP2X__
@@ -178,10 +193,16 @@ void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed)
        req = (void *)addr;
        if (need_exec)
                prot |= PROT_EXEC;
+       /* avoid MAP_FIXED, it overrides existing mappings..
        if (is_fixed)
                flags |= MAP_FIXED;
+       */
        if (size >= HUGETLB_THRESHOLD)
                flags |= MAP_HUGETLB;
+#ifdef MAP_JIT
+       if (need_exec)
+               flags |= MAP_JIT;
+#endif
 
        ret = mmap(req, size, prot, flags, -1, 0);
        if (ret == MAP_FAILED && (flags & MAP_HUGETLB)) {
@@ -193,13 +214,28 @@ void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed)
                }
                flags &= ~MAP_HUGETLB;
                ret = mmap(req, size, prot, flags, -1, 0);
+#ifdef MADV_HUGEPAGE
+               if (ret != MAP_FAILED && ((uintptr_t)ret & (2*1024*1024 - 1))) {
+                       // try to manually realign assuming bottom-to-top alloc
+                       munmap(ret, size);
+                       ret = (void *)((uintptr_t)ret & ~(2*1024*1024 - 1));
+                       ret = mmap(ret, size, prot, flags, -1, 0);
+               }
+               if (ret != MAP_FAILED)
+                       madvise(ret, size, MADV_HUGEPAGE);
+#endif
        }
        if (ret == MAP_FAILED)
                return NULL;
 
-       if (req != NULL && ret != req)
-               fprintf(stderr,
-                       "warning: mmaped to %p, requested %p\n", ret, req);
+       if (req != NULL && ret != req) {
+               fprintf(stderr, "%s: mmaped to %p, requested %p\n",
+                       is_fixed ? "error" : "warning", ret, req);
+               if (is_fixed) {
+                       munmap(ret, size);
+                       return NULL;
+               }
+       }
 
        return ret;
 }
@@ -208,9 +244,22 @@ void *plat_mremap(void *ptr, size_t oldsize, size_t newsize)
 {
        void *ret;
 
+#ifdef MREMAP_MAYMOVE
        ret = mremap(ptr, oldsize, newsize, MREMAP_MAYMOVE);
        if (ret == MAP_FAILED)
-               return NULL;
+#endif
+       {
+               fprintf(stderr, "mremap %p %zd %zd: ",
+                       ptr, oldsize, newsize);
+               perror(NULL);
+               // might be because huge pages can't be remapped,
+               // just make a new mapping
+               ret = plat_mmap(0, newsize, 0, 0);
+               if (ret == MAP_FAILED)
+                       return NULL;
+               memcpy(ret, ptr, oldsize);
+               munmap(ptr, oldsize);
+       }
        if (ret != ptr)
                printf("warning: mremap moved: %p -> %p\n", ptr, ret);