Author: Remi Meier <[email protected]>
Branch:
Changeset: r1344:69b4538466fc
Date: 2014-09-04 10:35 +0200
http://bitbucket.org/pypy/stmgc/changeset/69b4538466fc/
Log: add minimal privatization in signal handler
diff --git a/c8/stm/core.c b/c8/stm/core.c
--- a/c8/stm/core.c
+++ b/c8/stm/core.c
@@ -9,14 +9,31 @@
void _signal_handler(int sig, siginfo_t *siginfo, void *context)
{
- /* make PROT_READWRITE again and validate */
-
- if (siginfo->si_addr == NULL) { /* actual segfault */
+ char *addr = siginfo->si_addr;
+ dprintf(("si_addr: %p\n", addr));
+ if (addr == NULL) { /* actual segfault */
/* send to GDB */
kill(getpid(), SIGINT);
}
- /* didn't know what to do with it: send to GDB */
- kill(getpid(), SIGINT);
+ /* make PROT_READWRITE again and validate */
+ 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;
+
+ /* XXX: missing synchronisation: we may change protection, then
+ another thread changes it back, then we try to privatize that
+ calls page_copy() and traps */
+ mprotect(seg_base + pagenum * 4096UL, 4096, PROT_READ|PROT_WRITE);
+ page_privatize(pagenum);
+
+ /* XXX: ... what can go wrong when we abort from inside
+ the signal handler? */
+
+ /* make sure we are up to date in this (and all other) pages */
+ stm_validate(NULL);
+ return;
}
/* ############# commit log ############# */
@@ -125,11 +142,11 @@
for (i = 0; i < NB_SEGMENTS; i++) {
if (i == STM_SEGMENT->segment_num)
continue;
-
+ /* XXX: only do it if not already PROT_NONE */
char *segment_base = get_segment_base(i);
mprotect(segment_base + first_page * 4096,
(end_page - first_page + 1) * 4096, PROT_NONE);
- dprintf(("prot %lu, len=%lu in seg %d\n", first_page, (end_page -
first_page + 1), i));
+ dprintf(("prot %lu, len=%lu in seg %lu\n", first_page, (end_page -
first_page + 1), i));
}
LIST_APPEND(STM_PSEGMENT->modified_old_objects, obj);
diff --git a/c8/stm/core.h b/c8/stm/core.h
--- a/c8/stm/core.h
+++ b/c8/stm/core.h
@@ -95,6 +95,12 @@
get_segment_base(segment_num), STM_PSEGMENT);
}
+static inline int get_segment_of_linear_address(char *addr) {
+ assert(addr > stm_object_pages && addr < stm_object_pages + TOTAL_MEMORY);
+ return (addr - stm_object_pages) / (NB_PAGES * 4096UL);
+}
+
+
static bool _is_tl_registered(stm_thread_local_t *tl);
static bool _seems_to_be_running_transaction(void);
diff --git a/c8/stm/gcpage.c b/c8/stm/gcpage.c
--- a/c8/stm/gcpage.c
+++ b/c8/stm/gcpage.c
@@ -51,5 +51,7 @@
object_t *o = (object_t *)(p - stm_object_pages);
o->stm_flags = GCFLAG_WRITE_BARRIER;
+ dprintf(("allocate_old(%lu): %p, seg=%d\n", size_rounded_up, p,
+ get_segment_of_linear_address(p)));
return o;
}
diff --git a/c8/stm/pages.c b/c8/stm/pages.c
--- a/c8/stm/pages.c
+++ b/c8/stm/pages.c
@@ -68,3 +68,38 @@
count * 4096UL, pagenum);
}
}
+
+static void page_privatize(uintptr_t pagenum)
+{
+ /* check this thread's 'pages_privatized' bit */
+ uint64_t bitmask = 1UL << (STM_SEGMENT->segment_num - 1);
+ 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;
+ }
+
+ long i;
+ for (i = 0; i < NB_SEGMENTS; i++) {
+ spinlock_acquire(get_priv_segment(i)->privatization_lock);
+ }
+
+ /* 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 * STM_SEGMENT->segment_num + pagenum;
+ char *new_page = stm_object_pages + pagenum_in_file * 4096UL;
+ d_remap_file_pages(new_page, 4096, pagenum_in_file);
+
+ /* copy the content from the shared (segment 0) source */
+ pagecopy(new_page, stm_object_pages + pagenum * 4096UL);
+
+ for (i = NB_SEGMENTS-1; i >= 0; i--) {
+ spinlock_release(get_priv_segment(i)->privatization_lock);
+ }
+}
diff --git a/c8/stm/pages.h b/c8/stm/pages.h
--- a/c8/stm/pages.h
+++ b/c8/stm/pages.h
@@ -21,6 +21,8 @@
static struct page_shared_s pages_privatized[PAGE_FLAG_END - PAGE_FLAG_START];
static void pages_initialize_shared(uintptr_t pagenum, uintptr_t count);
+static void page_privatize(uintptr_t pagenum);
+
static inline bool is_private_page(long segnum, uintptr_t pagenum)
{
diff --git a/c8/stm/setup.c b/c8/stm/setup.c
--- a/c8/stm/setup.c
+++ b/c8/stm/setup.c
@@ -70,11 +70,11 @@
PROT_NONE);
if (i != 0) {
- /* let's give all pages to segment 0 at first and make them
- write-inaccessible everywhere else */
+ /* let's give all pages to segment 0 at first, all others
+ need to trap and look for the backup copy */
mprotect(segment_base + END_NURSERY_PAGE * 4096,
(NB_PAGES - END_NURSERY_PAGE) * 4096,
- PROT_READ);
+ PROT_NONE);
}
}
}
@@ -232,13 +232,12 @@
tl->prev = stm_all_thread_locals->prev;
stm_all_thread_locals->prev->next = tl;
stm_all_thread_locals->prev = tl;
- num = tl->prev->associated_segment_num;
+ num = (tl->prev->associated_segment_num + 1) % NB_SEGMENTS;
}
/* assign numbers consecutively, but that's for tests; we could also
assign the same number to all of them and they would get their own
numbers automatically. */
- num = (num + 1) % NB_SEGMENTS;
tl->associated_segment_num = num;
*_get_cpth(tl) = pthread_self();
_init_shadow_stack(tl);
diff --git a/c8/stm/sync.c b/c8/stm/sync.c
--- a/c8/stm/sync.c
+++ b/c8/stm/sync.c
@@ -142,3 +142,8 @@
set_gs_register(get_segment_base(tl->associated_segment_num));
assert(STM_SEGMENT->running_thread == tl);
}
+
+void _stm_test_switch_segment(int segnum)
+{
+ set_gs_register(get_segment_base(segnum));
+}
diff --git a/c8/stmgc.h b/c8/stmgc.h
--- a/c8/stmgc.h
+++ b/c8/stmgc.h
@@ -80,6 +80,7 @@
long stm_can_move(object_t *obj);
void _stm_test_switch(stm_thread_local_t *tl);
+void _stm_test_switch_segment(int segnum);
void _push_obj_to_other_segments(object_t *obj);
char *_stm_get_segment_base(long index);
diff --git a/c8/test/support.py b/c8/test/support.py
--- a/c8/test/support.py
+++ b/c8/test/support.py
@@ -51,6 +51,7 @@
long stm_can_move(object_t *obj);
char *_stm_real_address(object_t *o);
void _stm_test_switch(stm_thread_local_t *tl);
+void _stm_test_switch_segment(int segnum);
void clear_jmpbuf(stm_thread_local_t *tl);
long stm_start_transaction(stm_thread_local_t *tl);
@@ -395,6 +396,9 @@
lib.stm_setup()
self.tls = [_allocate_thread_local() for i in range(self.NB_THREADS)]
self.current_thread = 0
+ # force-switch back to segment 0 so that when we do something
+ # outside of transactions before the test, it happens in seg0
+ self.switch_to_segment(0)
def teardown_method(self, meth):
lib.stmcb_expand_marker = ffi.NULL
@@ -452,6 +456,9 @@
lib._stm_test_switch(tl2)
stm_validate() # can raise
+ def switch_to_segment(self, seg_num):
+ lib._stm_test_switch_segment(seg_num)
+
def push_root(self, o):
assert ffi.typeof(o) == ffi.typeof("object_t *")
tl = self.tls[self.current_thread]
diff --git a/c8/test/test_basic.py b/c8/test/test_basic.py
--- a/c8/test/test_basic.py
+++ b/c8/test/test_basic.py
@@ -56,7 +56,7 @@
def test_allocate_old(self):
lp1 = stm_allocate_old(16)
- self.switch(1)
+ self.switch(1) # actually has not much of an effect...
lp2 = stm_allocate_old(16)
assert lp1 != lp2
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit