Author: Remi Meier <[email protected]>
Branch: c8-new-page-handling
Changeset: r1393:b2fd01cfefe6
Date: 2014-09-19 10:46 +0200
http://bitbucket.org/pypy/stmgc/changeset/b2fd01cfefe6/

Log:    huge mess in progress

diff --git a/c8/stm/core.c b/c8/stm/core.c
--- a/c8/stm/core.c
+++ b/c8/stm/core.c
@@ -2,9 +2,135 @@
 # error "must be compiled via stmgc.c"
 #endif
 
-#include <signal.h>
 
+/* ############# signal handler ############# */
+static void _update_obj_from(int from_seg, object_t *obj);
 
+static void copy_bk_objs_from(int from_segnum, uintptr_t pagenum)
+{
+    acquire_modified_objs_lock(from_segnum);
+    struct tree_s *tree = get_priv_segment(from_segnum)->modified_old_objects;
+    wlog_t *item;
+    TREE_LOOP_FORWARD(tree, item); {
+        if (item->addr >= pagenum * 4096UL && item->addr < (pagenum + 1) * 
4096UL) {
+            object_t *obj = (object_t*)item->addr;
+            struct object_s* bk_obj = (struct object_s *)item->val;
+            size_t obj_size;
+
+            obj_size = stmcb_size_rounded_up(bk_obj);
+
+            memcpy_to_accessible_pages(STM_SEGMENT->segment_num,
+                                       obj, (char*)bk_obj, obj_size);
+
+            assert(obj->stm_flags & GCFLAG_WRITE_BARRIER); /* bk_obj never 
written */
+        }
+    } TREE_LOOP_END;
+
+    release_modified_objs_lock(from_segnum);
+}
+
+static void update_page_from_to(
+    uintptr_t pagenum, struct stm_commit_log_entry_s *from,
+    struct stm_commit_log_entry_s *to)
+{
+    assert(all_privatization_locks_acquired());
+
+    volatile struct stm_commit_log_entry_s *cl;
+    cl = (volatile struct stm_commit_log_entry_s *)from;
+
+    if (from == to)
+        return;
+
+    while ((cl = cl->next)) {
+        if ((uintptr_t)cl == -1)
+            return;
+
+        OPT_ASSERT(cl->segment_num >= 0 && cl->segment_num < NB_SEGMENTS);
+
+        object_t *obj;
+        size_t i = 0;
+        while ((obj = cl->written[i])) {
+            _update_obj_from(cl->segment_num, obj);
+
+            i++;
+        };
+
+        /* last fully validated entry */
+        if (cl == to)
+            return;
+    }
+}
+
+static void bring_page_up_to_date(uintptr_t pagenum)
+{
+    /* XXX: bad, but no deadlocks: */
+    acquire_all_privatization_locks();
+
+    long i;
+    int my_segnum = STM_SEGMENT->segment_num;
+
+    assert(get_page_status_in(my_segnum, pagenum) == PAGE_NO_ACCESS);
+
+    /* find who has the PAGE_SHARED */
+    int shared_page_holder = -1;
+    int shared_ref_count = 0;
+    for (i = 0; i < NB_SEGMENTS; i++) {
+        if (i == my_segnum)
+            continue;
+        if (get_page_status_in(i, pagenum) == PAGE_SHARED) {
+            shared_page_holder = i;
+            shared_ref_count++;
+        }
+    }
+    assert(shared_page_holder != -1);
+
+    /* XXX: for now, we don't try to get the single shared page. We simply
+       regard it as private for its holder. */
+    /* this assert should be true for now... */
+    assert(shared_ref_count == 1);
+
+    /* make our page private */
+    page_privatize_in(STM_SEGMENT->segment_num, pagenum);
+    volatile char *dummy = REAL_ADDRESS(STM_SEGMENT->segment_base, 
pagenum*4096UL);
+    *dummy = *dummy;            /* force copy-on-write from shared page */
+
+    /* if there were modifications in the page, revert them: */
+    copy_bk_objs_from(shared_page_holder, pagenum);
+
+    /* if not already newer, update page to our revision */
+    update_page_from_to(
+        pagenum, get_priv_segment(shared_page_holder)->last_commit_log_entry,
+        STM_PSEGMENT->last_commit_log_entry);
+
+    /* in case page is already newer, validate everything now to have a common
+       revision for all pages */
+    stm_validate(NULL);
+
+    release_all_privatization_locks();
+}
+
+static void _signal_handler(int sig, siginfo_t *siginfo, void *context)
+{
+    char *addr = siginfo->si_addr;
+    dprintf(("si_addr: %p\n", addr));
+    if (addr == NULL || addr < stm_object_pages || addr > 
stm_object_pages+TOTAL_MEMORY) {
+        /* actual segfault */
+        /* send to GDB (XXX) */
+        kill(getpid(), SIGINT);
+    }
+    /* XXX: should we save 'errno'? */
+
+
+    int segnum = get_segment_of_linear_address(addr);
+    OPT_ASSERT(segnum == STM_SEGMENT->segment_num);
+    dprintf(("-> segment: %d\n", segnum));
+    char *seg_base = STM_SEGMENT->segment_base;
+    uintptr_t pagenum = ((char*)addr - seg_base) / 4096UL;
+
+    bring_page_up_to_date(pagenum);
+
+    return;
+}
 
 /* ############# commit log ############# */
 
@@ -30,17 +156,10 @@
     }
 }
 
+
 static void _update_obj_from(int from_seg, object_t *obj)
 {
-    /* during validation this looks up the obj in the
-       from_seg (backup or normal) and copies the version
-       over the current segment's one */
     size_t obj_size;
-    char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
-    uintptr_t pagenum = (uintptr_t)obj / 4096UL;
-
-    assert(get_page_status_in(from_seg, pagenum) != PAGE_NO_ACCESS);
-    assert(get_page_status_in(STM_SEGMENT->segment_num, pagenum) != 
PAGE_NO_ACCESS);
 
     /* look the obj up in the other segment's modified_old_objects to
        get its backup copy: */
@@ -51,7 +170,10 @@
     TREE_FIND(tree, (uintptr_t)obj, item, goto not_found);
 
     obj_size = stmcb_size_rounded_up((struct object_s*)item->val);
-    memcpy(realobj, (char*)item->val, obj_size);
+
+    memcpy_to_accessible_pages(STM_SEGMENT->segment_num, obj,
+                               (char*)item->val, obj_size);
+
     assert(obj->stm_flags & GCFLAG_WRITE_BARRIER);
     release_modified_objs_lock(from_seg);
     return;
@@ -60,9 +182,11 @@
     /* copy from page directly (obj is unmodified) */
     obj_size = stmcb_size_rounded_up(
         (struct object_s*)REAL_ADDRESS(get_segment_base(from_seg), obj));
-    memcpy(realobj,
-           REAL_ADDRESS(get_segment_base(from_seg), obj),
-           obj_size);
+
+    memcpy_to_accessible_pages(STM_SEGMENT->segment_num, obj,
+                               REAL_ADDRESS(get_segment_base(from_seg), obj),
+                               obj_size);
+
     obj->stm_flags |= GCFLAG_WRITE_BARRIER; /* may already be gone */
     release_modified_objs_lock(from_seg);
 }
@@ -77,6 +201,7 @@
         assert((uintptr_t)STM_PSEGMENT->last_commit_log_entry->next == -1);
         return;
     }
+    assert(all_privatization_locks_acquired());
 
     volatile struct stm_commit_log_entry_s *cl, *prev_cl;
     cl = prev_cl = (volatile struct stm_commit_log_entry_s *)
diff --git a/c8/stm/core.h b/c8/stm/core.h
--- a/c8/stm/core.h
+++ b/c8/stm/core.h
@@ -6,6 +6,8 @@
 #include <sys/mman.h>
 #include <errno.h>
 #include <pthread.h>
+#include <signal.h>
+
 
 /************************************************************/
 
@@ -135,7 +137,7 @@
 static stm_thread_local_t *abort_with_mutex_no_longjmp(void);
 static void abort_data_structures_from_segment_num(int segment_num);
 
-
+static void _signal_handler(int sig, siginfo_t *siginfo, void *context);
 
 static inline void _duck(void) {
     /* put a call to _duck() between two instructions that set 0 into
@@ -165,3 +167,34 @@
 {
     spinlock_release(get_priv_segment(segnum)->modified_objs_lock);
 }
+
+
+static inline bool all_privatization_locks_acquired()
+{
+#ifndef NDEBUG
+    long l;
+    for (l = 0; l < NB_SEGMENTS; l++) {
+        if (!get_priv_segment(l)->privatization_lock)
+            return false;
+    }
+    return true;
+#else
+    abort();
+#endif
+}
+
+static inline void acquire_all_privatization_locks()
+{
+    long l;
+    for (l = 0; l < NB_SEGMENTS; l++) {
+        acquire_privatization_lock(l);
+    }
+}
+
+static inline void release_all_privatization_locks()
+{
+    long l;
+    for (l = NB_SEGMENTS-1; l >= 0; l--) {
+        release_privatization_lock(l);
+    }
+}
diff --git a/c8/stm/pages.c b/c8/stm/pages.c
--- a/c8/stm/pages.c
+++ b/c8/stm/pages.c
@@ -54,14 +54,10 @@
     /* call remap_file_pages() to make all pages in the range(pagenum,
        pagenum+count) PAGE_SHARED in segnum, and PAGE_NO_ACCESS in other 
segments */
 
-    dprintf(("pages_initialize_shared: 0x%ld - 0x%ld\n", pagenum,
-             pagenum + count));
-#ifndef NDEBUG
-    long l;
-    for (l = 0; l < NB_SEGMENTS; l++) {
-        assert(get_priv_segment(l)->privatization_lock);
-    }
-#endif
+    dprintf(("pages_initialize_shared: 0x%ld - 0x%ld\n", pagenum, pagenum + 
count));
+
+    assert(all_privatization_locks_acquired());
+
     assert(pagenum < NB_PAGES);
     if (count == 0)
         return;
@@ -85,43 +81,43 @@
 }
 
 
-/* static void page_privatize_in(int segnum, uintptr_t pagenum, char 
*initialize_from) */
-/* { */
-/* #ifndef NDEBUG */
-/*     long l; */
-/*     for (l = 0; l < NB_SEGMENTS; l++) { */
-/*         assert(get_priv_segment(l)->privatization_lock); */
-/*     } */
-/* #endif */
+static void page_privatize_in(int segnum, uintptr_t pagenum)
+{
+#ifndef NDEBUG
+    long l;
+    for (l = 0; l < NB_SEGMENTS; l++) {
+        assert(get_priv_segment(l)->privatization_lock);
+    }
+#endif
+    assert(get_page_status_in(segnum, pagenum) == PAGE_NO_ACCESS);
+    dprintf(("page_privatize(%lu) in seg:%d\n", pagenum, segnum));
 
-/*     /\* check this thread's 'pages_privatized' bit *\/ */
-/*     uint64_t bitmask = 1UL << segnum; */
-/*     volatile struct page_shared_s *ps = (volatile struct page_shared_s *) */
-/*         &pages_privatized[pagenum - PAGE_FLAG_START]; */
-/*     if (ps->by_segment & bitmask) { */
-/*         /\* the page is already privatized; nothing to do *\/ */
-/*         return; */
-/*     } */
+    char *addr = (char*)(get_virt_page_of(segnum, pagenum) * 4096UL);
+    char *result = mmap(
+        addr, 4096UL, PROT_READ | PROT_WRITE,
+        MAP_FIXED | MAP_PRIVATE | MAP_NORESERVE,
+        stm_object_pages_fd, get_file_page_of(pagenum));
+    if (result == MAP_FAILED)
+        stm_fatalerror("page_privatize_in failed (mmap): %m");
 
-/*     dprintf(("page_privatize(%lu) in seg:%d\n", pagenum, segnum)); */
+    set_page_status_in(segnum, pagenum, PAGE_PRIVATE);
+}
 
-/*     /\* add this thread's 'pages_privatized' bit *\/ */
-/*     ps->by_segment |= bitmask; */
 
-/*     /\* "unmaps" the page to make the address space location correspond */
-/*        again to its underlying file offset (XXX later we should again */
-/*        attempt to group together many calls to d_remap_file_pages() in */
-/*        succession) *\/ */
-/*     uintptr_t pagenum_in_file = NB_PAGES * segnum + pagenum; */
-/*     char *new_page = stm_object_pages + pagenum_in_file * 4096UL; */
+static void memcpy_to_accessible_pages(
+    int dst_segnum, object_t *dst_obj, char *src, size_t len)
+{
+    /* XXX: optimize */
 
-/*     /\* first write to the file page directly: *\/ */
-/*     ssize_t written = pwrite(stm_object_pages_fd, initialize_from, 4096UL, 
*/
-/*                              pagenum_in_file * 4096UL); */
-/*     if (written != 4096) */
-/*         stm_fatalerror("pwrite didn't write the whole page: %zd", written); 
*/
+    char *realobj = REAL_ADDRESS(get_segment_base(dst_segnum), dst_obj);
+    char *dst_end = realobj + len;
+    uintptr_t loc_addr = (uintptr_t)dst_obj;
 
-/*     /\* now remap virtual page in segment to the new file page *\/ */
-/*     write_fence(); */
-/*     d_remap_file_pages(new_page, 4096, pagenum_in_file); */
-/* } */
+    while (realobj != dst_end) {
+        if (get_page_status_in(dst_segnum, loc_addr / 4096UL) != 
PAGE_NO_ACCESS)
+            *realobj = *src;
+        realobj++;
+        loc_addr++;
+        src++;
+    }
+}
diff --git a/c8/stm/pages.h b/c8/stm/pages.h
--- a/c8/stm/pages.h
+++ b/c8/stm/pages.h
@@ -46,7 +46,23 @@
 static struct page_shared_s pages_status[NB_SHARED_PAGES];
 
 static void pages_initialize_shared_for(long segnum, uintptr_t pagenum, 
uintptr_t count);
-/* static void page_privatize_in(int segnum, uintptr_t pagenum, char 
*initialize_from); */
+static void page_privatize_in(int segnum, uintptr_t pagenum);
+static void memcpy_to_accessible_pages(int dst_segnum, object_t *dst_obj, char 
*src, size_t len);
+
+
+
+
+static inline uintptr_t get_virt_page_of(long segnum, uintptr_t pagenum)
+{
+    /* logical page -> virtual page */
+    return (uintptr_t)get_segment_base(segnum) / 4096UL + pagenum;
+}
+
+static inline uintptr_t get_file_page_of(uintptr_t pagenum)
+{
+    /* logical page -> file page */
+    return pagenum - PAGE_FLAG_START;
+}
 
 
 static inline uint8_t get_page_status_in(long segnum, uintptr_t pagenum)
@@ -54,7 +70,7 @@
     int seg_shift = segnum * 2;
     uint64_t bitmask = 3UL << seg_shift;
     volatile struct page_shared_s *ps = (volatile struct page_shared_s *)
-        &pages_status[pagenum - PAGE_FLAG_START];
+        &pages_status[get_file_page_of(pagenum)];
 
     return ((ps->by_segment & bitmask) >> seg_shift) & 3;
 }
@@ -65,16 +81,8 @@
 
     int seg_shift = segnum * 2;
     volatile struct page_shared_s *ps = (volatile struct page_shared_s *)
-        &pages_status[pagenum - PAGE_FLAG_START];
+        &pages_status[get_file_page_of(pagenum)];
 
     assert(status != get_page_status_in(segnum, pagenum));
     ps->by_segment |= status << seg_shift;
 }
-
-
-
-static inline uintptr_t get_virt_page_of(long segnum, uintptr_t pagenum)
-{
-    /* logical page -> virtual page */
-    return (uintptr_t)get_segment_base(segnum) / 4096UL + pagenum;
-}
diff --git a/c8/stm/setup.c b/c8/stm/setup.c
--- a/c8/stm/setup.c
+++ b/c8/stm/setup.c
@@ -2,8 +2,9 @@
 # error "must be compiled via stmgc.c"
 #endif
 
+#include <signal.h>
+#include <fcntl.h>           /* For O_* constants */
 
-#include <fcntl.h>           /* For O_* constants */
 static void setup_mmap(char *reason)
 {
     char name[] = "/__stmgc_c8__";
@@ -79,6 +80,21 @@
 }
 
 
+static void setup_signal_handler(void)
+{
+    struct sigaction act;
+    memset(&act, 0, sizeof(act));
+
+       act.sa_sigaction = &_signal_handler;
+       /* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, 
not sa_handler. */
+       act.sa_flags = SA_SIGINFO | SA_NODEFER;
+
+       if (sigaction(SIGSEGV, &act, NULL) < 0) {
+               perror ("sigaction");
+               abort();
+       }
+}
+
 void stm_setup(void)
 {
     /* Check that some values are acceptable */
@@ -103,6 +119,7 @@
     assert(stm_file_pages);
 
     setup_protection_settings();
+    setup_signal_handler();
 
     long i;
     for (i = 0; i < NB_SEGMENTS; i++) {
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to