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