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