Author: Remi Meier <[email protected]>
Branch:
Changeset: r1760:6f8794111ab4
Date: 2015-05-19 10:18 +0200
http://bitbucket.org/pypy/stmgc/changeset/6f8794111ab4/
Log: re-add some missing comments in stmgc.h
diff --git a/c8/stmgc.h b/c8/stmgc.h
--- a/c8/stmgc.h
+++ b/c8/stmgc.h
@@ -57,13 +57,16 @@
typedef struct stm_thread_local_s {
/* rewind_setjmp's interface */
rewind_jmp_thread rjthread;
+ /* every thread should handle the shadow stack itself */
struct stm_shadowentry_s *shadowstack, *shadowstack_base;
-
/* a generic optional thread-local object */
object_t *thread_local_obj;
-
+ /* in case this thread runs a transaction that aborts,
+ the following raw region of memory is cleared. */
char *mem_clear_on_abort;
size_t mem_bytes_to_clear_on_abort;
+ /* after an abort, some details about the abort are stored there.
+ (this field is not modified on a successful commit) */
long last_abort__bytes_in_nursery;
/* the next fields are handled internally by the library */
int associated_segment_num;
@@ -73,22 +76,9 @@
void *creating_pthread[2];
} stm_thread_local_t;
-#ifndef _STM_NURSERY_ZEROED
-#define _STM_NURSERY_ZEROED 0
-#endif
-#define _STM_GCFLAG_WRITE_BARRIER 0x01
-#define _STM_FAST_ALLOC (66*1024)
-#define _STM_NSE_SIGNAL_ABORT 1
-#define _STM_NSE_SIGNAL_MAX 2
-
-#define _STM_CARD_MARKED 1 /* should always be 1... */
-#define _STM_GCFLAG_CARDS_SET 0x8
-#define _STM_CARD_BITS 5 /* must be 5/6/7 for the pypy jit */
-#define _STM_CARD_SIZE (1 << _STM_CARD_BITS)
-#define _STM_MIN_CARD_COUNT 17
-#define _STM_MIN_CARD_OBJ_SIZE (_STM_CARD_SIZE * _STM_MIN_CARD_COUNT)
-
+/* this should use llvm's coldcc calling convention,
+ but it's not exposed to C code so far */
void _stm_write_slowpath(object_t *);
void _stm_write_slowpath_card(object_t *, uintptr_t);
object_t *_stm_allocate_slowpath(ssize_t);
@@ -96,6 +86,7 @@
void _stm_become_inevitable(const char*);
void _stm_collectable_safe_point(void);
+/* for tests, but also used in duhton: */
object_t *_stm_allocate_old(ssize_t size_rounded_up);
char *_stm_real_address(object_t *o);
#ifdef STM_TESTS
@@ -145,6 +136,24 @@
uint64_t _stm_total_allocated(void);
#endif
+
+#ifndef _STM_NURSERY_ZEROED
+#define _STM_NURSERY_ZEROED 0
+#endif
+
+#define _STM_GCFLAG_WRITE_BARRIER 0x01
+#define _STM_FAST_ALLOC (66*1024)
+#define _STM_NSE_SIGNAL_ABORT 1
+#define _STM_NSE_SIGNAL_MAX 2
+
+#define _STM_CARD_MARKED 1 /* should always be 1... */
+#define _STM_GCFLAG_CARDS_SET 0x8
+#define _STM_CARD_BITS 5 /* must be 5/6/7 for the pypy jit */
+#define _STM_CARD_SIZE (1 << _STM_CARD_BITS)
+#define _STM_MIN_CARD_COUNT 17
+#define _STM_MIN_CARD_OBJ_SIZE (_STM_CARD_SIZE * _STM_MIN_CARD_COUNT)
+
+
/* ==================== HELPERS ==================== */
#ifdef NDEBUG
#define OPT_ASSERT(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
@@ -165,30 +174,32 @@
*/
#define STM_NB_SEGMENTS 4
+/* Structure of objects
+ --------------------
+ Objects manipulated by the user program, and managed by this library,
+ must start with a "struct object_s" field. Pointers to any user object
+ must use the "TLPREFIX struct foo *" type --- don't forget TLPREFIX.
+ The best is to use typedefs like above.
+
+ The object_s part contains some fields reserved for the STM library.
+ Right now this is only four bytes.
+*/
struct object_s {
uint32_t stm_flags; /* reserved for the STM library */
};
-extern ssize_t stmcb_size_rounded_up(struct object_s *);
-void stmcb_trace(struct object_s *obj, void visit(object_t **));
-/* a special trace-callback that is only called for the marked
- ranges of indices (using stm_write_card(o, index)) */
-extern void stmcb_trace_cards(struct object_s *, void (object_t **),
- uintptr_t start, uintptr_t stop);
-/* this function will be called on objects that support cards.
- It returns the base_offset (in bytes) inside the object from
- where the indices start, and item_size (in bytes) for the size of
- one item */
-extern void stmcb_get_card_base_itemsize(struct object_s *,
- uintptr_t offset_itemsize[2]);
-/* returns whether this object supports cards. we will only call
- stmcb_get_card_base_itemsize on objs that do so. */
-extern long stmcb_obj_supports_cards(struct object_s *);
-
-
-
+/* The read barrier must be called whenever the object 'obj' is read.
+ It is not required to call it before reading: it can be delayed for a
+ bit, but we must still be in the same "scope": no allocation, no
+ transaction commit, nothing that can potentially collect or do a safe
+ point (like stm_write() on a different object). Also, if we might
+ have finished the transaction and started the next one, then
+ stm_read() needs to be called again. It can be omitted if
+ stm_write() is called, or immediately after getting the object from
+ stm_allocate(), as long as the rules above are respected.
+*/
__attribute__((always_inline))
static inline void stm_read(object_t *obj)
{
@@ -199,6 +210,11 @@
#define _STM_WRITE_CHECK_SLOWPATH(obj) \
UNLIKELY(((obj)->stm_flags & _STM_GCFLAG_WRITE_BARRIER) != 0)
+/* The write barrier must be called *before* doing any change to the
+ object 'obj'. If we might have finished the transaction and started
+ the next one, then stm_write() needs to be called again. It is not
+ necessary to call it immediately after stm_allocate().
+*/
__attribute__((always_inline))
static inline void stm_write(object_t *obj)
{
@@ -206,7 +222,14 @@
_stm_write_slowpath(obj);
}
-
+/* The following is a GC-optimized barrier that works on the granularity
+ of CARD_SIZE. It can be used on any array object, but it is only
+ useful with those that were internally marked with GCFLAG_HAS_CARDS.
+ It has the same purpose as stm_write() for TM and allows write-access
+ to a part of an object/array.
+ 'index' is the array-item-based position within the object, which
+ is measured in units returned by stmcb_get_card_base_itemsize().
+*/
__attribute__((always_inline))
static inline void stm_write_card(object_t *obj, uintptr_t index)
{
@@ -245,7 +268,34 @@
}
}
+/* Must be provided by the user of this library.
+ The "size rounded up" must be a multiple of 8 and at least 16.
+ "Tracing" an object means enumerating all GC references in it,
+ by invoking the callback passed as argument.
+*/
+extern ssize_t stmcb_size_rounded_up(struct object_s *);
+void stmcb_trace(struct object_s *obj, void visit(object_t **));
+/* a special trace-callback that is only called for the marked
+ ranges of indices (using stm_write_card(o, index)) */
+extern void stmcb_trace_cards(struct object_s *, void (object_t **),
+ uintptr_t start, uintptr_t stop);
+/* this function will be called on objects that support cards.
+ It returns the base_offset (in bytes) inside the object from
+ where the indices start, and item_size (in bytes) for the size of
+ one item */
+extern void stmcb_get_card_base_itemsize(struct object_s *,
+ uintptr_t offset_itemsize[2]);
+/* returns whether this object supports cards. we will only call
+ stmcb_get_card_base_itemsize on objs that do so. */
+extern long stmcb_obj_supports_cards(struct object_s *);
+
+
+
+/* Allocate an object of the given size, which must be a multiple
+ of 8 and at least 16. In the fast-path, this is inlined to just
+ a few assembler instructions.
+*/
__attribute__((always_inline))
static inline object_t *stm_allocate(ssize_t size_rounded_up)
{
@@ -267,21 +317,48 @@
return (object_t *)p;
}
-
+/* Allocate a weakref object. Weakref objects have a
+ reference to an object at the byte-offset
+ stmcb_size_rounded_up(obj) - sizeof(void*)
+ You must assign the reference before the next collection may happen.
+ After that, you must not mutate the reference anymore. However,
+ it can become NULL after any GC if the reference dies during that
+ collection.
+ NOTE: For performance, we assume stmcb_size_rounded_up(weakref)==16
+*/
object_t *stm_allocate_weakref(ssize_t size_rounded_up);
+/* stm_setup() needs to be called once at the beginning of the program.
+ stm_teardown() can be called at the end, but that's not necessary
+ and rather meant for tests.
+ */
void stm_setup(void);
void stm_teardown(void);
+/* The size of each shadow stack, in number of entries.
+ Must be big enough to accomodate all STM_PUSH_ROOTs! */
#define STM_SHADOW_STACK_DEPTH 163840
+
+/* Push and pop roots from/to the shadow stack. Only allowed inside
+ transaction. */
#define STM_PUSH_ROOT(tl, p) ((tl).shadowstack++->ss = (object_t *)(p))
#define STM_POP_ROOT(tl, p) ((p) = (typeof(p))((--(tl).shadowstack)->ss))
#define STM_POP_ROOT_RET(tl) ((--(tl).shadowstack)->ss)
+/* Every thread needs to have a corresponding stm_thread_local_t
+ structure. It may be a "__thread" global variable or something else.
+ Use the following functions at the start and at the end of a thread.
+ The user of this library needs to maintain the two shadowstack fields;
+ at any call to stm_allocate(), these fields should point to a range
+ of memory that can be walked in order to find the stack roots.
+*/
void stm_register_thread_local(stm_thread_local_t *tl);
void stm_unregister_thread_local(stm_thread_local_t *tl);
+/* At some key places, like the entry point of the thread and in the
+ function with the interpreter's dispatch loop, you need to declare
+ a local variable of type 'rewind_jmp_buf' and call these macros. */
#define stm_rewind_jmp_enterprepframe(tl, rjbuf) \
rewind_jmp_enterprepframe(&(tl)->rjthread, rjbuf, (tl)->shadowstack)
#define stm_rewind_jmp_enterframe(tl, rjbuf) \
@@ -303,37 +380,23 @@
rewind_jmp_enum_shadowstack(&(tl)->rjthread, callback)
+/* Starting and ending transactions. stm_read(), stm_write() and
+ stm_allocate() should only be called from within a transaction.
+ The stm_start_transaction() call returns the number of times it
+ returned, starting at 0. If it is > 0, then the transaction was
+ aborted and restarted this number of times. */
long stm_start_transaction(stm_thread_local_t *tl);
void stm_start_inevitable_transaction(stm_thread_local_t *tl);
-
void stm_commit_transaction(void);
/* Temporary fix? Call this outside a transaction. If there is an
inevitable transaction running somewhere else, wait until it finishes. */
void stm_wait_for_current_inevitable_transaction(void);
+/* Abort the currently running transaction. This function never
+ returns: it jumps back to the stm_start_transaction(). */
void stm_abort_transaction(void) __attribute__((noreturn));
-void stm_collect(long level);
-
-long stm_identityhash(object_t *obj);
-long stm_id(object_t *obj);
-void stm_set_prebuilt_identityhash(object_t *obj, long hash);
-
-long stm_can_move(object_t *obj);
-
-object_t *stm_setup_prebuilt(object_t *);
-object_t *stm_setup_prebuilt_weakref(object_t *);
-
-long stm_call_on_abort(stm_thread_local_t *, void *key, void callback(void *));
-long stm_call_on_commit(stm_thread_local_t *, void *key, void callback(void
*));
-
-static inline void stm_safe_point(void) {
- if (STM_SEGMENT->nursery_end <= _STM_NSE_SIGNAL_MAX)
- _stm_collectable_safe_point();
-}
-
-
#ifdef STM_NO_AUTOMATIC_SETJMP
int stm_is_inevitable(void);
#else
@@ -352,7 +415,64 @@
_stm_become_inevitable(msg);
}
+/* Forces a safe-point if needed. Normally not needed: this is
+ automatic if you call stm_allocate(). */
+static inline void stm_safe_point(void) {
+ if (STM_SEGMENT->nursery_end <= _STM_NSE_SIGNAL_MAX)
+ _stm_collectable_safe_point();
+}
+
+/* Forces a collection. */
+void stm_collect(long level);
+
+
+/* Prepare an immortal "prebuilt" object managed by the GC. Takes a
+ pointer to an 'object_t', which should not actually be a GC-managed
+ structure but a real static structure. Returns the equivalent
+ GC-managed pointer. Works by copying it into the GC pages, following
+ and fixing all pointers it contains, by doing stm_setup_prebuilt() on
+ each of them recursively. (Note that this will leave garbage in the
+ static structure, but it should never be used anyway.) */
+object_t *stm_setup_prebuilt(object_t *);
+/* The same, if the prebuilt object is actually a weakref. */
+object_t *stm_setup_prebuilt_weakref(object_t *);
+
+/* Hash, id. The id is just the address of the object (of the address
+ where it *will* be after the next minor collection). The hash is the
+ same, mangled -- except on prebuilt objects, where it can be
+ controlled for each prebuilt object individually. (Useful uor PyPy) */
+long stm_identityhash(object_t *obj);
+long stm_id(object_t *obj);
+void stm_set_prebuilt_identityhash(object_t *obj, long hash);
+
+/* Returns 1 if the object can still move (it's in the nursery), or 0
+ otherwise. After a minor collection no object can move any more. */
+long stm_can_move(object_t *obj);
+
+/* If the current transaction aborts later, invoke 'callback(key)'. If
+ the current transaction commits, then the callback is forgotten. You
+ can only register one callback per key. You can call
+ 'stm_call_on_abort(key, NULL)' to cancel an existing callback
+ (returns 0 if there was no existing callback to cancel).
+ Note: 'key' must be aligned to a multiple of 8 bytes. */
+long stm_call_on_abort(stm_thread_local_t *, void *key, void callback(void *));
+/* If the current transaction commits later, invoke 'callback(key)'. If
+ the current transaction aborts, then the callback is forgotten. Same
+ restrictions as stm_call_on_abort(). If the transaction is or becomes
+ inevitable, 'callback(key)' is called immediately. */
+long stm_call_on_commit(stm_thread_local_t *, void *key, void callback(void
*));
+
+
+/* Similar to stm_become_inevitable(), but additionally suspend all
+ other threads. A very heavy-handed way to make sure that no other
+ transaction is running concurrently. Avoid as much as possible.
+ Other transactions will continue running only after this transaction
+ commits. (xxx deprecated and may be removed) */
void stm_become_globally_unique_transaction(stm_thread_local_t *tl, const char
*msg);
+
+/* Moves the transaction forward in time by validating the read and
+ write set with all commits that happened since the last validation
+ (explicit or implicit). */
void stm_validate(void);
/* Temporarily stop all the other threads, by waiting until they
@@ -411,8 +531,8 @@
/* The markers pushed in the shadowstack are an odd number followed by a
regular object pointer. */
typedef struct {
- uintptr_t odd_number;
- object_t *object;
+ uintptr_t odd_number; /* marker odd number, or 0 if marker is missing */
+ object_t *object; /* marker object, or NULL if marker is missing */
} stm_loc_marker_t;
extern void (*stmcb_timing_event)(stm_thread_local_t *tl, /* the local thread
*/
enum stm_event_e event,
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit