Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r166:e47c6c61565d
Date: 2013-06-17 13:35 +0200
http://bitbucket.org/pypy/stmgc/changeset/e47c6c61565d/

Log:    Copy some more code from c3.

diff --git a/c4/et.c b/c4/et.c
--- a/c4/et.c
+++ b/c4/et.c
@@ -1344,7 +1344,6 @@
 
 struct tx_public_descriptor *stm_descriptor_array[MAX_THREADS] = {0};
 static revision_t descriptor_array_free_list = 0;
-static revision_t descriptor_array_lock = 0;
 
 int DescriptorInit(void)
 {
@@ -1360,7 +1359,7 @@
       revision_t i;
       struct tx_descriptor *d = stm_malloc(sizeof(struct tx_descriptor));
       memset(d, 0, sizeof(struct tx_descriptor));
-      spinlock_acquire(descriptor_array_lock, 1);
+      stmgcpage_acquire_global_lock();
 
       struct tx_public_descriptor *pd;
       i = descriptor_array_free_list;
@@ -1398,7 +1397,8 @@
       fprintf(stderr, "[%lx] pthread %lx starting\n",
               (long)d->public_descriptor_index, (long)pthread_self());
 
-      spinlock_release(descriptor_array_lock);
+      stmgcpage_init_tls();
+      stmgcpage_release_global_lock();
       return 1;
     }
   else
@@ -1415,12 +1415,13 @@
     gcptrlist_delete(&d->public_descriptor->stolen_objects);
     gcptrlist_delete(&d->public_descriptor->stolen_young_stubs);
 
-    spinlock_acquire(descriptor_array_lock, 1);
+    stmgcpage_acquire_global_lock();
+    stmgcpage_done_tls();
     i = d->public_descriptor_index;
     assert(stm_descriptor_array[i] == d->public_descriptor);
     d->public_descriptor->free_list_next = descriptor_array_free_list;
     descriptor_array_free_list = i;
-    spinlock_release(descriptor_array_lock);
+    stmgcpage_release_global_lock();
 
     thread_descriptor = NULL;
 
diff --git a/c4/gcpage.c b/c4/gcpage.c
--- a/c4/gcpage.c
+++ b/c4/gcpage.c
@@ -1,6 +1,16 @@
 #include "stmimpl.h"
 
 
+/* This maps each small request size to the number of blocks of this size
+   that fit in a page. */
+static int nblocks_for_size[GC_SMALL_REQUESTS];
+
+/* A mutex for major collections and other global operations */
+static pthread_mutex_t mutex_gc_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* A count-down: when it reaches 0, run the next major collection */
+static revision_t countdown_next_major_coll = GC_MIN;
+
 /* For statistics */
 static uintptr_t count_global_pages;
 
@@ -13,3 +23,155 @@
     default: return -1;
     }
 }
+
+
+/***** Support code *****/
+
+void stmgcpage_acquire_global_lock(void)
+{
+    int err = pthread_mutex_lock(&mutex_gc_lock);
+    assert(err == 0);
+}
+
+void stmgcpage_release_global_lock(void)
+{
+    int err = pthread_mutex_unlock(&mutex_gc_lock);
+    assert(err == 0);
+}
+
+
+/***** Initialization logic *****/
+
+static void init_global_data(void)
+{
+    int i;
+    for (i = 1; i < GC_SMALL_REQUESTS; i++) {
+        nblocks_for_size[i] =
+            (GC_PAGE_SIZE - sizeof(page_header_t)) / (WORD * i);
+    }
+}
+
+void stmgcpage_init_tls(void)
+{
+    if (nblocks_for_size[1] == 0)
+        init_global_data();
+}
+
+void stmgcpage_done_tls(void)
+{
+    /* Send to the shared area all my pages.  For now we don't extract
+       the information about which locations are free or not; we just
+       leave it to the next major GC to figure them out. */
+#if 0
+    struct tx_public_descriptor *gcp = LOCAL_GCPAGES();
+
+    gcp->gcp_next = finished_thread_gcpages;
+    finished_thread_gcpages = gcp;
+    count_global_pages += gcp->count_pages;*/
+#endif
+}
+
+
+/***** Thread-local allocator *****/
+
+void stmgcpage_reduce_threshold(size_t size)
+{
+    revision_t next, target;
+ restart:
+    next = ACCESS_ONCE(countdown_next_major_coll);
+    if (next >= size)
+        target = next - size;
+    else
+        target = 0;
+    if (!bool_cas(&countdown_next_major_coll, next, target))
+        goto restart;
+}
+
+static gcptr allocate_new_page(int size_class)
+{
+    /* Adjust the threshold; the caller is responsible for detecting the
+       condition that the threshold reached 0. */
+    stmgcpage_reduce_threshold(GC_PAGE_SIZE);
+
+    /* Allocate and return a new page for the given size_class. */
+    page_header_t *page = (page_header_t *)stm_malloc(GC_PAGE_SIZE);
+    if (!page) {
+        fprintf(stderr, "allocate_new_page: out of memory!\n");
+        abort();
+    }
+    struct tx_public_descriptor *gcp = LOCAL_GCPAGES();
+    gcp->count_pages++;
+
+    /* Initialize the fields of the resulting page */
+    page->next_page = gcp->pages_for_size[size_class];
+    gcp->pages_for_size[size_class] = page;
+
+    /* Initialize the chained list in the page */
+    gcptr head = (gcptr)(page + 1);
+    gcptr current, next;
+    int count = nblocks_for_size[size_class];
+    int nsize = size_class * WORD;
+    int i;
+    current = head;
+    for (i = 0; i < count - 1; i++) {
+        next = (gcptr)(((char *)current) + nsize);
+        assert(!(GCFLAG_VISITED & DEBUG_WORD(0xDD)));
+        current->h_tid = DEBUG_WORD(0xDD);  /*anything without GCFLAG_VISITED*/
+        current->h_revision = (revision_t)next;
+        //stm_dbgmem_not_used(current, nsize, 0);
+        current = next;
+    }
+    current->h_tid = DEBUG_WORD(0xDD);
+    current->h_revision = (revision_t)gcp->free_loc_for_size[size_class];
+    //stm_dbgmem_not_used(current, nsize, 0);
+    gcp->free_loc_for_size[size_class] = head;
+    return head;
+}
+
+gcptr stmgcpage_malloc(size_t size)
+{
+    /* Allocates an object of the given 'size'.  This will never run
+       a collection: you need to call stmgcpage_possibly_major_collect(0)
+       when you know you're at a safe point. */
+    if (size <= GC_SMALL_REQUEST_THRESHOLD) {
+        gcptr result;
+        struct tx_public_descriptor *gcp = LOCAL_GCPAGES();
+        int size_class = (size + WORD - 1) / WORD;
+        assert(0 < size_class && size_class < GC_SMALL_REQUESTS);
+
+        /* The result is simply 'free_loc_for_size[size_class]' */
+        result = gcp->free_loc_for_size[size_class];
+        if (!result) {
+            result = allocate_new_page(size_class);
+        }
+        gcp->free_loc_for_size[size_class] = (gcptr)result->h_revision;
+        //stm_dbgmem_used_again(result, size_class * WORD, 0);
+        return result;
+    }
+    else {
+        fprintf(stderr, "XXX stmgcpage_malloc: too big!\n");
+        abort();
+    }
+}
+
+static unsigned char random_char = 42;
+
+void stmgcpage_free(gcptr obj)
+{
+    size_t size = stmcb_size(obj);
+    if (size <= GC_SMALL_REQUEST_THRESHOLD) {
+        struct tx_public_descriptor *gcp = LOCAL_GCPAGES();
+        int size_class = (size + WORD - 1) / WORD;
+        assert(0 < size_class && size_class < GC_SMALL_REQUESTS);
+
+        /* We simply re-add the object to the right chained list */
+        assert(obj->h_tid = DEBUG_WORD(random_char++));
+        obj->h_revision = (revision_t)gcp->free_loc_for_size[size_class];
+        gcp->free_loc_for_size[size_class] = obj;
+        //stm_dbgmem_not_used(obj, size_class * WORD, 0);
+    }
+    else {
+        fprintf(stderr, "XXX stmgcpage_free: too big!\n");
+        abort();
+    }
+}
diff --git a/c4/gcpage.h b/c4/gcpage.h
--- a/c4/gcpage.h
+++ b/c4/gcpage.h
@@ -13,7 +13,8 @@
 /* Linux's glibc is good at 'malloc(1023*WORD)': the blocks ("pages") it
    returns are exactly 1024 words apart, reserving only one extra word
    for its internal data.  Here we assume that even on other systems it
-   will not use more than three words. */
+   will not use more than three words.  It results in pages of 1020
+   WORDs, which is a number that divides well by many small values. */
 #ifndef GC_PAGE_SIZE
 #define GC_PAGE_SIZE   (1021 * WORD)
 #endif
@@ -65,8 +66,10 @@
 #define LOCAL_GCPAGES()  (thread_descriptor->public_descriptor)
 
 
-void stmgcpage_init_tls(void);
-void stmgcpage_done_tls(void);
+void stmgcpage_acquire_global_lock(void);
+void stmgcpage_release_global_lock(void);
+void stmgcpage_init_tls(void);   /* must hold the global lock */
+void stmgcpage_done_tls(void);   /* must hold the global lock */
 gcptr stmgcpage_malloc(size_t size);
 void stmgcpage_free(gcptr obj);
 void stmgcpage_add_prebuilt_root(gcptr obj);
diff --git a/c4/test/support.py b/c4/test/support.py
--- a/c4/test/support.py
+++ b/c4/test/support.py
@@ -55,8 +55,8 @@
 
     /* extra non-public code */
     void *stm_malloc(size_t size);
-    //gcptr stmgcpage_malloc(size_t size);
-    //void stmgcpage_free(gcptr obj);
+    gcptr stmgcpage_malloc(size_t size);
+    void stmgcpage_free(gcptr obj);
     long stmgcpage_count(int quantity);
     //void stmgcpage_possibly_major_collect(int);
     revision_t stm_global_cur_time(void);
@@ -107,7 +107,7 @@
     #define GCFLAG_STUB              ...
     #define GCFLAG_PRIVATE_FROM_PROTECTED  ...
     #define ABRT_MANUAL              ...
-    //typedef struct { ...; } page_header_t;
+    typedef struct { ...; } page_header_t;
 ''')
 
 lib = ffi.verify(r'''
@@ -266,7 +266,7 @@
 
 HDR = ffi.sizeof("struct stm_object_s")
 WORD = lib.WORD
-#PAGE_ROOM = lib.GC_PAGE_SIZE - ffi.sizeof("page_header_t")
+PAGE_ROOM = lib.GC_PAGE_SIZE - ffi.sizeof("page_header_t")
 for name in lib.__dict__:
     if name.startswith('GCFLAG_') or name.startswith('PREBUILT_'):
         globals()[name] = getattr(lib, name)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to