Author: Armin Rigo <[email protected]>
Branch: stmgc-c7
Changeset: r74378:8bb7d5b1d1a9
Date: 2014-11-07 19:07 +0100
http://bitbucket.org/pypy/pypy/changeset/8bb7d5b1d1a9/
Log: import stmgc/ece6317ba186 [hashtable]
diff --git a/rpython/translator/stm/src_stm/revision
b/rpython/translator/stm/src_stm/revision
--- a/rpython/translator/stm/src_stm/revision
+++ b/rpython/translator/stm/src_stm/revision
@@ -1,1 +1,1 @@
-3a8ef5f741ab
+ece6317ba186
diff --git a/rpython/translator/stm/src_stm/stm/core.c
b/rpython/translator/stm/src_stm/stm/core.c
--- a/rpython/translator/stm/src_stm/stm/core.c
+++ b/rpython/translator/stm/src_stm/stm/core.c
@@ -373,6 +373,7 @@
assert(tree_is_cleared(STM_PSEGMENT->nursery_objects_shadows));
assert(tree_is_cleared(STM_PSEGMENT->callbacks_on_commit_and_abort[0]));
assert(tree_is_cleared(STM_PSEGMENT->callbacks_on_commit_and_abort[1]));
+ assert(list_is_empty(STM_PSEGMENT->young_objects_with_light_finalizers));
assert(STM_PSEGMENT->objects_pointing_to_nursery == NULL);
assert(STM_PSEGMENT->large_overflow_objects == NULL);
assert(STM_PSEGMENT->finalizers == NULL);
@@ -973,6 +974,8 @@
(int)pseg->transaction_state);
}
+ abort_finalizers(pseg);
+
/* throw away the content of the nursery */
long bytes_in_nursery = throw_away_nursery(pseg);
@@ -1061,8 +1064,6 @@
/* invoke the callbacks */
invoke_and_clear_user_callbacks(1); /* for abort */
- abort_finalizers();
-
if (is_abort(STM_SEGMENT->nursery_end)) {
/* done aborting */
STM_SEGMENT->nursery_end = pause_signalled ? NSE_SIGPAUSE
diff --git a/rpython/translator/stm/src_stm/stm/finalizer.c
b/rpython/translator/stm/src_stm/stm/finalizer.c
--- a/rpython/translator/stm/src_stm/stm/finalizer.c
+++ b/rpython/translator/stm/src_stm/stm/finalizer.c
@@ -59,28 +59,73 @@
STM_PSEGMENT->finalizers = NULL;
}
-static void _abort_finalizers(void)
+static void abort_finalizers(struct stm_priv_segment_info_s *pseg)
{
/* like _commit_finalizers(), but forget everything from the
current transaction */
- if (STM_PSEGMENT->finalizers->run_finalizers != NULL) {
- if (STM_PSEGMENT->finalizers->running_next != NULL) {
- *STM_PSEGMENT->finalizers->running_next = (uintptr_t)-1;
+ if (pseg->finalizers != NULL) {
+ if (pseg->finalizers->run_finalizers != NULL) {
+ if (pseg->finalizers->running_next != NULL) {
+ *pseg->finalizers->running_next = (uintptr_t)-1;
+ }
+ list_free(pseg->finalizers->run_finalizers);
}
- list_free(STM_PSEGMENT->finalizers->run_finalizers);
+ list_free(pseg->finalizers->objects_with_finalizers);
+ free(pseg->finalizers);
+ pseg->finalizers = NULL;
}
- list_free(STM_PSEGMENT->finalizers->objects_with_finalizers);
- free(STM_PSEGMENT->finalizers);
- STM_PSEGMENT->finalizers = NULL;
+
+ /* call the light finalizers for objects that are about to
+ be forgotten from the current transaction */
+ char *old_gs_register = STM_SEGMENT->segment_base;
+ bool must_fix_gs = old_gs_register != pseg->pub.segment_base;
+
+ struct list_s *lst = pseg->young_objects_with_light_finalizers;
+ long i, count = list_count(lst);
+ if (lst > 0) {
+ for (i = 0; i < count; i++) {
+ object_t *obj = (object_t *)list_item(lst, i);
+ assert(_is_young(obj));
+ if (must_fix_gs) {
+ set_gs_register(pseg->pub.segment_base);
+ must_fix_gs = false;
+ }
+ stmcb_light_finalizer(obj);
+ }
+ list_clear(lst);
+ }
+
+ /* also deals with overflow objects: they are at the tail of
+ old_objects_with_light_finalizers (this list is kept in order
+ and we cannot add any already-committed object) */
+ lst = pseg->old_objects_with_light_finalizers;
+ count = list_count(lst);
+ while (count > 0) {
+ object_t *obj = (object_t *)list_item(lst, --count);
+ if (!IS_OVERFLOW_OBJ(pseg, obj))
+ break;
+ lst->count = count;
+ if (must_fix_gs) {
+ set_gs_register(pseg->pub.segment_base);
+ must_fix_gs = false;
+ }
+ stmcb_light_finalizer(obj);
+ }
+
+ if (STM_SEGMENT->segment_base != old_gs_register)
+ set_gs_register(old_gs_register);
}
void stm_enable_light_finalizer(object_t *obj)
{
- if (_is_young(obj))
+ if (_is_young(obj)) {
LIST_APPEND(STM_PSEGMENT->young_objects_with_light_finalizers, obj);
- else
+ }
+ else {
+ assert(_is_from_same_transaction(obj));
LIST_APPEND(STM_PSEGMENT->old_objects_with_light_finalizers, obj);
+ }
}
object_t *stm_allocate_with_finalizer(ssize_t size_rounded_up)
@@ -109,7 +154,7 @@
struct list_s *lst = STM_PSEGMENT->young_objects_with_light_finalizers;
long i, count = list_count(lst);
for (i = 0; i < count; i++) {
- object_t* obj = (object_t *)list_item(lst, i);
+ object_t *obj = (object_t *)list_item(lst, i);
assert(_is_young(obj));
object_t *TLPREFIX *pforwarded_array = (object_t *TLPREFIX *)obj;
@@ -139,7 +184,7 @@
long i, count = list_count(lst);
lst->count = 0;
for (i = 0; i < count; i++) {
- object_t* obj = (object_t *)list_item(lst, i);
+ object_t *obj = (object_t *)list_item(lst, i);
if (!mark_visited_test(obj)) {
/* not marked: object dies */
/* we're calling the light finalizer in the same
@@ -346,6 +391,24 @@
LIST_FREE(_finalizer_emptystack);
}
+static void mark_visit_from_finalizer1(char *base, struct finalizers_s *f)
+{
+ if (f != NULL && f->run_finalizers != NULL) {
+ LIST_FOREACH_R(f->run_finalizers, object_t * /*item*/,
+ mark_visit_object(item, base));
+ }
+}
+
+static void mark_visit_from_finalizer_pending(void)
+{
+ long j;
+ for (j = 1; j <= NB_SEGMENTS; j++) {
+ struct stm_priv_segment_info_s *pseg = get_priv_segment(j);
+ mark_visit_from_finalizer1(pseg->pub.segment_base, pseg->finalizers);
+ }
+ mark_visit_from_finalizer1(stm_object_pages, &g_finalizers);
+}
+
static void _execute_finalizers(struct finalizers_s *f)
{
if (f->run_finalizers == NULL)
diff --git a/rpython/translator/stm/src_stm/stm/finalizer.h
b/rpython/translator/stm/src_stm/stm/finalizer.h
--- a/rpython/translator/stm/src_stm/stm/finalizer.h
+++ b/rpython/translator/stm/src_stm/stm/finalizer.h
@@ -7,6 +7,7 @@
uintptr_t *running_next;
};
+static void mark_visit_from_finalizer_pending(void);
static void deal_with_young_objects_with_finalizers(void);
static void deal_with_old_objects_with_finalizers(void);
static void deal_with_objects_with_finalizers(void);
@@ -15,18 +16,13 @@
static void teardown_finalizer(void);
static void _commit_finalizers(void);
-static void _abort_finalizers(void);
+static void abort_finalizers(struct stm_priv_segment_info_s *);
#define commit_finalizers() do { \
if (STM_PSEGMENT->finalizers != NULL) \
_commit_finalizers(); \
} while (0)
-#define abort_finalizers() do { \
- if (STM_PSEGMENT->finalizers != NULL) \
- _abort_finalizers(); \
-} while (0)
-
/* regular finalizers (objs from already-committed transactions) */
static struct finalizers_s g_finalizers;
diff --git a/rpython/translator/stm/src_stm/stm/gcpage.c
b/rpython/translator/stm/src_stm/stm/gcpage.c
--- a/rpython/translator/stm/src_stm/stm/gcpage.c
+++ b/rpython/translator/stm/src_stm/stm/gcpage.c
@@ -345,6 +345,8 @@
LIST_APPEND(mark_objects_to_trace, obj);
}
+#define TRACE_FOR_MAJOR_COLLECTION (&mark_record_trace)
+
static void mark_trace(object_t *obj, char *segment_base)
{
assert(list_is_empty(mark_objects_to_trace));
@@ -353,7 +355,7 @@
/* trace into the object (the version from 'segment_base') */
struct object_s *realobj =
(struct object_s *)REAL_ADDRESS(segment_base, obj);
- stmcb_trace(realobj, &mark_record_trace);
+ stmcb_trace(realobj, TRACE_FOR_MAJOR_COLLECTION);
if (list_is_empty(mark_objects_to_trace))
break;
@@ -630,6 +632,7 @@
mark_visit_from_modified_objects();
mark_visit_from_markers();
mark_visit_from_roots();
+ mark_visit_from_finalizer_pending();
LIST_FREE(mark_objects_to_trace);
/* finalizer support: will mark as WL_VISITED all objects with a
diff --git a/rpython/translator/stm/src_stm/stm/nursery.c
b/rpython/translator/stm/src_stm/stm/nursery.c
--- a/rpython/translator/stm/src_stm/stm/nursery.c
+++ b/rpython/translator/stm/src_stm/stm/nursery.c
@@ -45,6 +45,10 @@
tree_contains(STM_PSEGMENT->young_outside_nursery, (uintptr_t)obj));
}
+static inline bool _is_from_same_transaction(object_t *obj) {
+ return _is_young(obj) || IS_OVERFLOW_OBJ(STM_PSEGMENT, obj);
+}
+
long stm_can_move(object_t *obj)
{
/* 'long' return value to avoid using 'bool' in the public interface */
@@ -330,6 +334,7 @@
}
+#define TRACE_FOR_MINOR_COLLECTION (&minor_trace_if_young)
static inline void _collect_now(object_t *obj)
{
@@ -343,7 +348,7 @@
outside the nursery, possibly forcing nursery objects out and
adding them to 'objects_pointing_to_nursery' as well. */
char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
- stmcb_trace((struct object_s *)realobj, &minor_trace_if_young);
+ stmcb_trace((struct object_s *)realobj, TRACE_FOR_MINOR_COLLECTION);
obj->stm_flags |= GCFLAG_WRITE_BARRIER;
}
diff --git a/rpython/translator/stm/src_stm/stmgc.c
b/rpython/translator/stm/src_stm/stmgc.c
--- a/rpython/translator/stm/src_stm/stmgc.c
+++ b/rpython/translator/stm/src_stm/stmgc.c
@@ -18,6 +18,7 @@
#include "stm/marker.h"
#include "stm/prof.h"
#include "stm/finalizer.h"
+#include "stm/hashtable.h"
#include "stm/misc.c"
#include "stm/list.c"
@@ -40,3 +41,4 @@
#include "stm/prof.c"
#include "stm/rewind_setjmp.c"
#include "stm/finalizer.c"
+#include "stm/hashtable.c"
diff --git a/rpython/translator/stm/src_stm/stmgc.h
b/rpython/translator/stm/src_stm/stmgc.h
--- a/rpython/translator/stm/src_stm/stmgc.h
+++ b/rpython/translator/stm/src_stm/stmgc.h
@@ -509,7 +509,7 @@
/* Support for light finalizers. This is a simple version of
finalizers that guarantees not to do anything fancy, like not
resurrecting objects. */
-void (*stmcb_light_finalizer)(object_t *);
+extern void (*stmcb_light_finalizer)(object_t *);
void stm_enable_light_finalizer(object_t *);
/* Support for regular finalizers. Unreachable objects with
@@ -526,9 +526,30 @@
transaction. For older objects, the finalizer is called from a
random thread between regular transactions, in a new custom
transaction. */
-void (*stmcb_finalizer)(object_t *);
+extern void (*stmcb_finalizer)(object_t *);
object_t *stm_allocate_with_finalizer(ssize_t size_rounded_up);
+/* Hashtables. Keys are 64-bit unsigned integers, values are
+ 'object_t *'. Note that the type 'stm_hashtable_t' is not an
+ object type at all; you need to allocate and free it explicitly.
+ If you want to embed the hashtable inside an 'object_t' you
+ probably need a light finalizer to do the freeing. */
+typedef struct stm_hashtable_s stm_hashtable_t;
+stm_hashtable_t *stm_hashtable_create(void);
+void stm_hashtable_free(stm_hashtable_t *);
+object_t *stm_hashtable_read(object_t *, stm_hashtable_t *, uintptr_t key);
+void stm_hashtable_write(object_t *, stm_hashtable_t *, uintptr_t key,
+ object_t *nvalue, stm_thread_local_t *);
+extern uint32_t stm_hashtable_entry_userdata;
+void stm_hashtable_tracefn(stm_hashtable_t *, void (object_t **));
+
+struct stm_hashtable_entry_s {
+ struct object_s header;
+ uint32_t userdata;
+ uintptr_t index;
+ object_t *object;
+};
+
/* ==================== END ==================== */
#endif
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit