Author: Armin Rigo <[email protected]>
Branch: c7-refactor
Changeset: r717:9f7a1243b6ad
Date: 2014-02-10 16:34 +0100
http://bitbucket.org/pypy/stmgc/changeset/9f7a1243b6ad/

Log:    in-progress

diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -1,6 +1,16 @@
+#ifndef _STM_CORE_H_
+# error "must be compiled via stmgc.c"
+#endif
 
 
 void _stm_write_slowpath(object_t *obj)
 {
     abort();
 }
+
+void stm_start_transaction(stm_thread_local_t *tl, stm_jmpbuf_t *jmpbuf)
+{
+    /* GS invalid before this point! */
+    _stm_stop_safe_point(LOCK_COLLECT|THREAD_YIELD);
+    
+}
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -1,6 +1,13 @@
+#define _STM_CORE_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+
 
 #define NB_PAGES            (1500*256)    // 1500MB
-#define NB_THREADS          2
+#define NB_REGIONS          2
 #define MAP_PAGES_FLAGS     (MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE)
 #define LARGE_OBJECT_WORDS  36
 #define NB_NURSERY_PAGES    1024          // 4MB
@@ -8,13 +15,13 @@
 #define NURSERY_SECTION_SIZE  (24*4096)
 
 
-#define TOTAL_MEMORY          (NB_PAGES * 4096UL * NB_THREADS)
+#define TOTAL_MEMORY          (NB_PAGES * 4096UL * NB_REGIONS)
 #define READMARKER_END        ((NB_PAGES * 4096UL) >> 4)
-#define START_OBJECT_PAGE     ((READMARKER_END + 4095) / 4096UL)
-#define START_NURSERY_PAGE    START_OBJECT_PAGE
-#define READMARKER_START      ((START_OBJECT_PAGE * 4096UL) >> 4)
-#define START_READMARKER_PAGE (READMARKER_START / 4096UL)
-#define STOP_NURSERY_PAGE     (START_NURSERY_PAGE + NB_NURSERY_PAGES)
+#define FIRST_OBJECT_PAGE     ((READMARKER_END + 4095) / 4096UL)
+#define FIRST_NURSERY_PAGE    FIRST_OBJECT_PAGE
+#define READMARKER_START      ((FIRST_OBJECT_PAGE * 4096UL) >> 4)
+#define FIRST_READMARKER_PAGE (READMARKER_START / 4096UL)
+#define END_NURSERY_PAGE      (FIRST_NURSERY_PAGE + NB_NURSERY_PAGES)
 
 
 enum {
@@ -43,5 +50,22 @@
     struct stm_region_info_s pub;
 };
 
+static char *stm_object_pages;
+static stm_thread_local_t *stm_thread_locals = NULL;
 
-#define REAL_ADDRESS(thread_base, src)   ((thread_base) + (uintptr_t)(src))
+
+#define REAL_ADDRESS(region_base, src)   ((region_base) + (uintptr_t)(src))
+
+static inline char *get_region_base(long region_num) {
+    return stm_object_pages + region_num * (NB_PAGES * 4096UL);
+}
+
+static inline struct stm_region_info_s *get_region(long region_num) {
+    return (struct stm_region_info_s *)REAL_ADDRESS(
+        get_region_base(region_num), STM_PREGION);
+}
+
+static inline struct stm_priv_region_info_s *get_priv_region(long region_num) {
+    return (struct stm_priv_region_info_s *)REAL_ADDRESS(
+        get_region_base(region_num), STM_PREGION);
+}
diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c
--- a/c7/stm/gcpage.c
+++ b/c7/stm/gcpage.c
@@ -1,3 +1,7 @@
+#ifndef _STM_CORE_H_
+# error "must be compiled via stmgc.c"
+#endif
+
 
 stm_char *_stm_allocate_slowpath(ssize_t size_rounded_up)
 {
diff --git a/c7/stm/misc.c b/c7/stm/misc.c
--- a/c7/stm/misc.c
+++ b/c7/stm/misc.c
@@ -1,4 +1,6 @@
-#include <stdlib.h>
+#ifndef _STM_CORE_H_
+# error "must be compiled via stmgc.c"
+#endif
 
 
 char *_stm_real_address(object_t *o)
@@ -6,7 +8,7 @@
     if (o == NULL)
         return NULL;
 
-    assert(START_OBJECT_PAGE * 4096UL <= (uintptr_t)o
+    assert(FIRST_OBJECT_PAGE * 4096UL <= (uintptr_t)o
            && (uintptr_t)o < NB_PAGES * 4096UL);
     return REAL_ADDRESS(STM_REGION->region_base, o);
 }
@@ -17,7 +19,7 @@
         return NULL;
 
     uintptr_t res = ptr - STM_REGION->region_base;
-    assert(START_OBJECT_PAGE * 4096UL <= res
+    assert(FIRST_OBJECT_PAGE * 4096UL <= res
            && res < NB_PAGES * 4096UL);
     return (object_t*)res;
 }
diff --git a/c7/stm/pages.c b/c7/stm/pages.c
new file mode 100644
--- /dev/null
+++ b/c7/stm/pages.c
@@ -0,0 +1,30 @@
+#ifndef _STM_CORE_H_
+# error "must be compiled via stmgc.c"
+#endif
+
+
+static void pages_initialize_shared(uintptr_t pagenum, uintptr_t count)
+{
+    /* call remap_file_pages() to make all pages in the
+       range(pagenum, pagenum+count) refer to the same
+       physical range of pages from region 0 */
+    long i;
+    for (i = 1; i < NB_REGIONS; i++) {
+        char *region_base = get_region_base(i);
+        int res = remap_file_pages(region_base + pagenum * 4096UL,
+                                   count * 4096UL,
+                                   0, pagenum, 0);
+        if (res != 0) {
+            perror("remap_file_pages");
+            abort();
+        }
+    }
+    for (; count > 0; count--) {
+        flag_page_private[pagenum++] = SHARED_PAGE;
+    }
+}
+
+static void _pages_privatize(uintptr_t pagenum, uintptr_t count)
+{
+    abort();
+}
diff --git a/c7/stm/pages.h b/c7/stm/pages.h
new file mode 100644
--- /dev/null
+++ b/c7/stm/pages.h
@@ -0,0 +1,31 @@
+
+enum {
+    /* The page is not in use.  Assume that each region sees its own copy. */
+    FREE_PAGE=0,
+
+    /* The page is shared by all threads.  Each region sees the same
+       physical page (the one that is within the region 0 mmap address). */
+    SHARED_PAGE,
+
+    /* Page being in the process of privatization */
+    REMAPPING_PAGE,
+
+    /* Page private for each thread */
+    PRIVATE_PAGE,
+
+};      /* used for flag_page_private */
+
+
+static uint8_t flag_page_private[NB_PAGES];
+
+
+static void _pages_privatize(uintptr_t pagenum, uintptr_t count);
+static void pages_initialize_shared(uintptr_t pagenum, uintptr_t count);
+
+inline static void pages_privatize(uintptr_t pagenum, uintptr_t count) {
+    while (flag_page_private[pagenum + count - 1] == PRIVATE_PAGE) {
+        if (!--count)
+            return;
+    }
+    _pages_privatize(pagenum, count);
+}
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -1,3 +1,6 @@
+#ifndef _STM_CORE_H_
+# error "must be compiled via stmgc.c"
+#endif
 
 
 void stm_setup(void)
@@ -7,84 +10,93 @@
     _stm_reset_pages();
 
     inevitable_lock = 0;
-    
+#endif
+
     /* Check that some values are acceptable */
-    assert(4096 <= ((uintptr_t)_STM_TL));
-    assert(((uintptr_t)_STM_TL) == ((uintptr_t)_STM_TL));
-    assert(((uintptr_t)_STM_TL) + sizeof(*_STM_TL) <= 8192);
+    assert(4096 <= ((uintptr_t)STM_REGION));
+    assert((uintptr_t)STM_REGION == (uintptr_t)STM_PREGION);
+    assert(((uintptr_t)STM_PREGION) + sizeof(*STM_PREGION) <= 8192);
     assert(2 <= FIRST_READMARKER_PAGE);
     assert(FIRST_READMARKER_PAGE * 4096UL <= READMARKER_START);
     assert(READMARKER_START < READMARKER_END);
     assert(READMARKER_END <= 4096UL * FIRST_OBJECT_PAGE);
     assert(FIRST_OBJECT_PAGE < NB_PAGES);
-    assert((NB_NURSERY_PAGES * 4096) % NURSERY_SECTION == 0);
 
-    object_pages = mmap(NULL, TOTAL_MEMORY,
-                        PROT_READ | PROT_WRITE,
-                        MAP_PAGES_FLAGS, -1, 0);
-    if (object_pages == MAP_FAILED) {
-        perror("object_pages mmap");
+    stm_object_pages = mmap(NULL, TOTAL_MEMORY,
+                            PROT_READ | PROT_WRITE,
+                            MAP_PAGES_FLAGS, -1, 0);
+    if (stm_object_pages == MAP_FAILED) {
+        perror("stm_object_pages mmap");
         abort();
     }
 
     long i;
-    for (i = 0; i < NB_THREADS; i++) {
-        char *thread_base = get_thread_base(i);
+    for (i = 0; i < NB_REGIONS; i++) {
+        char *region_base = get_region_base(i);
 
-        /* In each thread's section, the first page is where TLPREFIX'ed
+        /* In each region, the first page is where TLPREFIX'ed
            NULL accesses land.  We mprotect it so that accesses fail. */
-        mprotect(thread_base, 4096, PROT_NONE);
+        mprotect(region_base, 4096, PROT_NONE);
 
-        /* Fill the TLS page (page 1) with 0xDD */
-        memset(REAL_ADDRESS(thread_base, 4096), 0xDD, 4096);
-        /* Make a "hole" at _STM_TL / _STM_TL */
-        memset(REAL_ADDRESS(thread_base, _STM_TL), 0, sizeof(*_STM_TL));
+        /* Fill the TLS page (page 1) with 0xDD, for debugging */
+        memset(REAL_ADDRESS(region_base, 4096), 0xDD, 4096);
+        /* Make a "hole" at STM_PREGION */
+        memset(REAL_ADDRESS(region_base, STM_PREGION), 0,
+               sizeof(*STM_PREGION));
 
         /* Pages in range(2, FIRST_READMARKER_PAGE) are never used */
         if (FIRST_READMARKER_PAGE > 2)
-            mprotect(thread_base + 8192, (FIRST_READMARKER_PAGE - 2) * 4096UL,
-                         PROT_NONE);
+            mprotect(region_base + 8192, (FIRST_READMARKER_PAGE - 2) * 4096UL,
+                     PROT_NONE);
 
-        struct _thread_local1_s *th =
-            (struct _thread_local1_s *)REAL_ADDRESS(thread_base, _STM_TL);
-
-        th->thread_num = i;
-        th->thread_base = thread_base;
-
-        if (i > 0) {
-            int res;
-            res = remap_file_pages(
-                    thread_base + FIRST_AFTER_NURSERY_PAGE * 4096UL,
-                    (NB_PAGES - FIRST_AFTER_NURSERY_PAGE) * 4096UL,
-                    0, FIRST_AFTER_NURSERY_PAGE, 0);
-
-            if (res != 0) {
-                perror("remap_file_pages");
-                abort();
-            }
-        }
+        struct stm_priv_region_info_s *pr = get_priv_region(i);
+        pr->pub.region_num = i;
+        pr->pub.region_base = region_base;
     }
 
-    for (i = FIRST_NURSERY_PAGE; i < FIRST_AFTER_NURSERY_PAGE; i++)
-        stm_set_page_flag(i, PRIVATE_PAGE); /* nursery is private.
-                                                or should it be UNCOMMITTED??? 
*/
-    
-    num_threads_started = 0;
+    /* Make the nursery pages shared.  The other pages are
+       shared lazily, as remap_file_pages() takes a relatively
+       long time for each page. */
+    pages_initialize_shared(FIRST_NURSERY_PAGE, NB_NURSERY_PAGES);
 
-    assert(HEAP_PAGES < NB_PAGES - FIRST_AFTER_NURSERY_PAGE);
-    assert(HEAP_PAGES > 10);
-
-    uintptr_t first_heap = stm_pages_reserve(HEAP_PAGES);
-    char *heap = REAL_ADDRESS(get_thread_base(0), first_heap * 4096UL); 
-    assert(memset(heap, 0xcd, HEAP_PAGES * 4096)); // testing
+#if 0
     stm_largemalloc_init(heap, HEAP_PAGES * 4096UL);
-
-    for (i = 0; i < NB_THREADS; i++) {
-        _stm_setup_static_thread();
-    }
 #endif
 }
 
 void stm_teardown(void)
 {
+    /* This function is called during testing, but normal programs don't
+       need to call it. */
+    munmap(stm_object_pages, TOTAL_MEMORY);
+    stm_object_pages = NULL;
+
+    memset(flag_page_private, 0, sizeof(flag_page_private));
 }
+
+void stm_register_thread_local(stm_thread_local_t *tl)
+{
+    if (stm_thread_locals == NULL) {
+        stm_thread_locals = tl->next = tl->prev = tl;
+    }
+    else {
+        tl->next = stm_thread_locals;
+        tl->prev = stm_thread_locals->prev;
+        stm_thread_locals->prev->next = tl;
+        stm_thread_locals->prev = tl;
+    }
+    tl->associated_region = get_region(0);
+}
+
+void stm_unregister_thread_local(stm_thread_local_t *tl)
+{
+    if (tl == stm_thread_locals) {
+        stm_thread_locals = stm_thread_locals->next;
+        if (tl == stm_thread_locals) {
+            stm_thread_locals = NULL;
+            return;
+        }
+    }
+    tl->prev->next = tl->next;
+    tl->next->prev = tl->prev;
+}
diff --git a/c7/stmgc.c b/c7/stmgc.c
--- a/c7/stmgc.c
+++ b/c7/stmgc.c
@@ -1,7 +1,10 @@
+#define _GNU_SOURCE
 #include "stmgc.h"
 #include "stm/core.h"
+#include "stm/pages.h"
 
 #include "stm/misc.c"
 #include "stm/core.c"
+#include "stm/pages.c"
 #include "stm/gcpage.c"
 #include "stm/setup.c"
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -42,9 +42,10 @@
 
 struct stm_region_info_s {
     uint8_t transaction_read_version;
+    int region_num;
+    char *region_base;
     stm_char *nursery_current;
     uintptr_t nursery_section_end;
-    char *region_base;
     struct stm_thread_local_s *running_thread;
     stm_jmpbuf_t *jmpbuf_ptr;
 };
@@ -54,7 +55,7 @@
     /* every thread should handle the shadow stack itself */
     object_t **shadowstack, **shadowstack_base;
     /* the next fields are handled automatically by the library */
-    stm_region_info_t *running_in_region;
+    struct stm_region_info_s *associated_region;
     struct stm_thread_local_s *prev, *next;
 } stm_thread_local_t;
 
@@ -147,10 +148,9 @@
 void stm_commit_transaction(void);
 void stm_abort_transaction(void);
 
-#define STM_START_TRANSACTION(tl)  ({                   \
-    stm_jmpbuf_t _buf;                                  \
-    int _restart = __builtin_setjmp(_buf);              \
-    stm_start_transaction(tl, _buf);                    \
+#define STM_START_TRANSACTION(tl, jmpbuf)  ({           \
+    int _restart = __builtin_setjmp(jmpbuf);            \
+    stm_start_transaction(tl, jmpbuf);                  \
    _restart;                                            \
 })
 
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -9,8 +9,11 @@
 parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
 source_files = [os.path.join(parent_dir, "stmgc.c")]
-all_files = [os.path.join(parent_dir, _n) for _n in os.listdir(parent_dir)
-             if _n.endswith('.h') or _n.endswith('.c')]
+all_files = [os.path.join(parent_dir, "stmgc.h"),
+             os.path.join(parent_dir, "stmgc.c")] + [
+    os.path.join(parent_dir, 'stm', _n)
+        for _n in os.listdir(os.path.join(parent_dir, 'stm'))
+            if _n.endswith('.h') or _n.endswith('.c')]
 
 _pycache_ = os.path.join(parent_dir, 'test', '__pycache__')
 if os.path.exists(_pycache_):
@@ -27,6 +30,7 @@
 ffi = cffi.FFI()
 ffi.cdef("""
 typedef ... object_t;
+typedef ... stm_jmpbuf_t;
 #define SIZEOF_MYOBJ ...
 
 typedef struct {
@@ -45,14 +49,15 @@
 bool _checked_stm_write(object_t *obj);
 bool _stm_was_read(object_t *obj);
 bool _stm_was_written(object_t *obj);
-""")
 
-
-TEMPORARILY_DISABLED = """
 void stm_register_thread_local(stm_thread_local_t *tl);
 void stm_unregister_thread_local(stm_thread_local_t *tl);
 
 void stm_start_transaction(stm_thread_local_t *tl, stm_jmpbuf_t *jmpbuf);
+""")
+
+
+TEMPORARILY_DISABLED = """
 void stm_start_inevitable_transaction(stm_thread_local_t *tl);
 void stm_commit_transaction(void);
 void stm_abort_transaction(void);
@@ -355,9 +360,6 @@
 def stm_pop_root():
     return lib.stm_pop_root()
 
-def stm_start_transaction():
-    lib.stm_start_transaction(ffi.cast("jmpbufptr_t*", -1))
-
 def stm_stop_transaction():
     if lib._stm_stop_transaction():
         raise Conflict()
@@ -394,31 +396,34 @@
 def stm_get_flags(o):
     return lib._stm_get_flags(o)
 
+def _allocate_thread_local():
+    tl = ffi.new("stm_thread_local_t *")
+    lib.stm_register_thread_local(tl)
+    return tl
+
 
 class BaseTest(object):
 
     def setup_method(self, meth):
         lib.stm_setup()
-##        lib.stm_setup_thread()
-##        lib.stm_setup_thread()
-##        lib._stm_restore_local_state(0)
-##        self.current_thread = 0
+        self.tls = [_allocate_thread_local(), _allocate_thread_local()]
+        self.current_thread = 0
+        self.running_transaction = set()
 
     def teardown_method(self, meth):
-##        if self.current_thread != 1:
-##            self.switch(1)
-##        if lib._stm_is_in_transaction():
-##            stm_stop_transaction()
+        for n in sorted(self.running_transaction):
+            self.switch(n)
+            self.abort_transaction()
+        for tl in self.tls:
+            lib.stm_unregister_thread_local(tl)
+        lib.stm_teardown()
 
-##        self.switch(0)
-##        if lib._stm_is_in_transaction():
-##            stm_stop_transaction()
-
-##        lib._stm_restore_local_state(1)
-##        lib._stm_teardown_thread()
-##        lib._stm_restore_local_state(0)
-##        lib._stm_teardown_thread()
-        lib.stm_teardown()
+    def start_transaction(self):
+        n = self.current_thread
+        assert n not in self.running_transaction
+        tl = self.tls[n]
+        lib.stm_start_transaction(tl, ffi.cast("stm_jmpbuf_t *", -1))
+        self.running_transaction.add(n)
 
     def switch(self, thread_num):
         assert thread_num != self.current_thread
@@ -428,5 +433,3 @@
         lib._stm_restore_local_state(thread_num)
         if lib._stm_is_in_transaction():
             stm_stop_safe_point() # can raise Conflict
-
-        
diff --git a/c7/test/test_basic.py b/c7/test/test_basic.py
--- a/c7/test/test_basic.py
+++ b/c7/test/test_basic.py
@@ -7,7 +7,7 @@
         pass
 
     def test_thread_local_allocations(self):
-        stm_start_transaction()
+        self.start_transaction()
         lp1 = stm_allocate(16)
         lp2 = stm_allocate(16)
         assert is_in_nursery(lp1)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to