Ancient
view release on metacpan or search on metacpan
xs/doubly/doubly.c view on Meta::CPAN
/*
* doubly.c - Thread-safe doubly linked list with SV registry
*
* Architecture following slot.c pattern:
* - Dynamic SV-based node storage (no serialization)
* - Index-based linking for thread safety (indices clone safely)
* - Full API compatibility with Doubly module
*/
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "doubly_compat.h"
/* ============================================
Data Structures
============================================ */
/* Node storage - index-based linking for thread safety */
typedef struct DoublyNodeSlot {
SV* data; /* Direct SV* - no serialization needed */
IV prev_idx; /* Index of prev node (-1 = none) */
IV next_idx; /* Index of next node (-1 = none) */
IV list_idx; /* Which list this node belongs to */
IV node_id; /* Stable ID for Perl object references */
#ifdef USE_ITHREADS
void* data_interp; /* Interpreter that owns data SV */
#endif
} DoublyNodeSlot;
/* List metadata */
typedef struct DoublyListMeta {
IV head_idx; /* Index of first node (-1 = empty placeholder) */
IV tail_idx; /* Index of last node */
IV length; /* Number of nodes with data */
IV refcount; /* Reference count for GC */
int destroyed; /* Flag to mark as destroyed */
} DoublyListMeta;
/* Global registries */
static DoublyListMeta* g_lists = NULL;
static IV g_lists_size = 0;
static IV g_lists_count = 0;
static DoublyNodeSlot* g_nodes = NULL;
static IV g_nodes_size = 0;
static IV g_nodes_count = 0;
static IV g_next_node_id = 1;
/* Free list for node reuse */
static IV* g_free_nodes = NULL;
static IV g_free_nodes_size = 0;
static IV g_free_nodes_count = 0;
/* Free list for list reuse */
static IV* g_free_lists = NULL;
static IV g_free_lists_size = 0;
static IV g_free_lists_count = 0;
/* Thread safety */
#ifdef USE_ITHREADS
static perl_mutex doubly_mutex;
static int doubly_mutex_initialized = 0;
#define DOUBLY_LOCK() MUTEX_LOCK(&doubly_mutex)
#define DOUBLY_UNLOCK() MUTEX_UNLOCK(&doubly_mutex)
#else
#define DOUBLY_LOCK()
#define DOUBLY_UNLOCK()
#endif
static int doubly_initialized = 0;
/* ============================================
Custom OPs for hot paths
============================================ */
static XOP doubly_data_get_xop;
static XOP doubly_data_set_xop;
static XOP doubly_length_xop;
xs/doubly/doubly.c view on Meta::CPAN
XSRETURN(1);
}
static XS(xs_destroy) {
dXSARGS;
HV* hash;
SV** id_sv;
IV list_idx;
if (items < 1) croak("Usage: doubly::destroy(self)");
hash = (HV*)SvRV(ST(0));
id_sv = hv_fetch(hash, "_id", 3, 0);
list_idx = id_sv ? SvIV(*id_sv) : -1;
list_destroy(aTHX_ list_idx);
XSRETURN_EMPTY;
}
static XS(xs_DESTROY) {
dXSARGS;
HV* hash;
SV** id_sv;
IV list_idx;
#ifdef USE_ITHREADS
SV** owner_tid_sv;
UV owner_tid;
UV my_tid;
#endif
PERL_UNUSED_VAR(items);
/* Skip cleanup during global destruction */
if (PL_dirty) {
XSRETURN_EMPTY;
}
hash = (HV*)SvRV(ST(0));
id_sv = hv_fetch(hash, "_id", 3, 0);
list_idx = id_sv ? SvIV(*id_sv) : -1;
#ifdef USE_ITHREADS
owner_tid_sv = hv_fetch(hash, "_owner_tid", 10, 0);
owner_tid = owner_tid_sv ? SvUV(*owner_tid_sv) : 0;
my_tid = PTR2UV(PERL_GET_THX);
/* Always decrement refcount - list_decref handles SV ownership internally.
* This prevents memory leaks from cloned objects that never get cleaned up. */
list_decref(aTHX_ list_idx);
(void)owner_tid; /* Suppress unused variable warning */
(void)my_tid;
#else
list_decref(aTHX_ list_idx);
#endif
XSRETURN_EMPTY;
}
static XS(xs_CLONE_SKIP) {
dXSARGS;
PERL_UNUSED_VAR(items);
/* Return 1 - do NOT clone doubly objects to new threads.
* Each thread must create its own lists. Sharing lists across
* threads is not supported. */
XSRETURN_IV(1);
}
/* ============================================
Boot
============================================ */
XS_EXTERNAL(boot_doubly) {
dXSBOOTARGSXSAPIVERCHK;
CV *method_cv;
SV *ckobj;
PERL_UNUSED_VAR(items);
doubly_init(aTHX);
/* Register custom OPs */
XopENTRY_set(&doubly_data_get_xop, xop_name, "doubly_data_get");
XopENTRY_set(&doubly_data_get_xop, xop_desc, "doubly data getter");
Perl_custom_op_register(aTHX_ pp_doubly_data_get, &doubly_data_get_xop);
XopENTRY_set(&doubly_data_set_xop, xop_name, "doubly_data_set");
XopENTRY_set(&doubly_data_set_xop, xop_desc, "doubly data setter");
Perl_custom_op_register(aTHX_ pp_doubly_data_set, &doubly_data_set_xop);
XopENTRY_set(&doubly_length_xop, xop_name, "doubly_length");
XopENTRY_set(&doubly_length_xop, xop_desc, "doubly length");
Perl_custom_op_register(aTHX_ pp_doubly_length, &doubly_length_xop);
XopENTRY_set(&doubly_next_xop, xop_name, "doubly_next");
XopENTRY_set(&doubly_next_xop, xop_desc, "doubly next");
Perl_custom_op_register(aTHX_ pp_doubly_next, &doubly_next_xop);
XopENTRY_set(&doubly_prev_xop, xop_name, "doubly_prev");
XopENTRY_set(&doubly_prev_xop, xop_desc, "doubly prev");
Perl_custom_op_register(aTHX_ pp_doubly_prev, &doubly_prev_xop);
XopENTRY_set(&doubly_start_xop, xop_name, "doubly_start");
XopENTRY_set(&doubly_start_xop, xop_desc, "doubly start");
Perl_custom_op_register(aTHX_ pp_doubly_start, &doubly_start_xop);
XopENTRY_set(&doubly_end_xop, xop_name, "doubly_end");
XopENTRY_set(&doubly_end_xop, xop_desc, "doubly end");
Perl_custom_op_register(aTHX_ pp_doubly_end, &doubly_end_xop);
XopENTRY_set(&doubly_is_start_xop, xop_name, "doubly_is_start");
XopENTRY_set(&doubly_is_start_xop, xop_desc, "doubly is_start");
Perl_custom_op_register(aTHX_ pp_doubly_is_start, &doubly_is_start_xop);
XopENTRY_set(&doubly_is_end_xop, xop_name, "doubly_is_end");
XopENTRY_set(&doubly_is_end_xop, xop_desc, "doubly is_end");
Perl_custom_op_register(aTHX_ pp_doubly_is_end, &doubly_is_end_xop);
/* Register XS functions */
newXS("doubly::new", xs_new, __FILE__);
newXS("doubly::add", xs_add, __FILE__);
newXS("doubly::bulk_add", xs_bulk_add, __FILE__);
newXS("doubly::remove_from_start", xs_remove_from_start, __FILE__);
newXS("doubly::remove_from_end", xs_remove_from_end, __FILE__);
newXS("doubly::remove", xs_remove, __FILE__);
newXS("doubly::remove_from_pos", xs_remove_from_pos, __FILE__);
( run in 0.738 second using v1.01-cache-2.11-cpan-f889d44b568 )