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