/* The definition of a dispatcher, stored in the registry. */ struct MVMDispDefinition { /* The ID of the dispatcher, used to look it up. */ MVMString *id; /* The dispatch callback, for when no entry is found in the cache. */ MVMObject *dispatch; /* The resume callback, for resumable dispatchers, when no resume entry * is found in the cache. */ MVMObject *resume; }; /* The dispatcher registry. The dispatcher definitions live in their own * pieces of memory, so we can reference them and know they won't move. We * then store an array of pointers to those. The position in the table is * determined by hashing the ID. If the table needs to grow, we safepoint * reallocate it. Thus we only need a lock for the purpose of guarding new * dispatcher registrations, and lookups are lock-free. We don't need to * worry over hash randomization and so forth here; the dispatchers are * registered by a program's runtime support, not on data from the outside * world. */ struct MVMDispRegistry { /* The current table, held at a level of indirection for safe updates. */ MVMDispRegistryTable *table; /* Lock for serializing updates to the set of dispatchers. */ uv_mutex_t mutex_update; }; struct MVMDispRegistryTable { /* The table of dispatcher definitions, safepoint * reallocated (thus why not using MVM_VECTOR). */ MVMDispDefinition **dispatchers; /* The number of allocated dispatcher entries and the number of * registered dispatchers. */ MVMuint32 alloc_dispatchers; MVMuint32 num_dispatchers; }; void MVM_disp_registry_init(MVMThreadContext *tc); void MVM_disp_registry_register(MVMThreadContext *tc, MVMString *id, MVMObject *dispatch, MVMObject *resume); MVMDispDefinition * MVM_disp_registry_find(MVMThreadContext *tc, MVMString *id); void MVM_disp_registry_mark(MVMThreadContext *tc, MVMGCWorklist *worklist); void MVM_disp_registry_describe(MVMThreadContext *tc, MVMHeapSnapshotState *snapshot); void MVM_disp_registry_destroy(MVMThreadContext *tc);