versions threads modules
[p5sagit/p5-mst-13.2.git] / ext / threads / shared / shared.xs
CommitLineData
afe38520 1/* shared.xs
68795e93 2 *
afe38520 3 * Copyright (c) 2001-2002, Larry Wall
68795e93 4 *
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Artistic License, as specified in the README file.
7 *
21312124 8 * "Hand any two wizards a piece of rope and they would instinctively pull in
9 * opposite directions."
10 * --Sourcery
11 *
12 * Contributed by Arthur Bergman arthur@contiller.se
13 * pulled in the (an)other direction by Nick Ing-Simmons nick@ing-simmons.net
14 */
68795e93 15
16#define PERL_NO_GET_CONTEXT
b050c948 17#include "EXTERN.h"
18#include "perl.h"
19#include "XSUB.h"
20
73e09c8f 21#ifdef USE_ITHREADS
22
21312124 23#define SHAREDSvPTR(a) ((a)->sv)
24
25/*
26 * The shared things need an intepreter to live in ...
27 */
28PerlInterpreter *PL_sharedsv_space; /* The shared sv space */
29/* To access shared space we fake aTHX in this scope and thread's context */
30#define SHARED_CONTEXT PERL_SET_CONTEXT((aTHX = PL_sharedsv_space))
31
32/* So we need a way to switch back to the caller's context... */
33/* So we declare _another_ copy of the aTHX variable ... */
34#define dTHXc PerlInterpreter *caller_perl = aTHX
35/* and use it to switch back */
36#define CALLER_CONTEXT PERL_SET_CONTEXT((aTHX = caller_perl))
37
38/*
39 * Only one thread at a time is allowed to mess with shared space.
40 */
a446a88f 41
6d56dc1c 42typedef struct
43{
44 perl_mutex mutex;
6d56dc1c 45 PerlInterpreter *owner;
46 I32 locks;
6b85e4fe 47 perl_cond cond;
48#ifdef DEBUG_LOCKS
49 char * file;
50 int line;
51#endif
6d56dc1c 52} recursive_lock_t;
53
54recursive_lock_t PL_sharedsv_lock; /* Mutex protecting the shared sv space */
55
56void
57recursive_lock_init(pTHX_ recursive_lock_t *lock)
58{
59 Zero(lock,1,recursive_lock_t);
60 MUTEX_INIT(&lock->mutex);
61 COND_INIT(&lock->cond);
62}
63
579f9913 64recursive_lock_destroy(pTHX_ recursive_lock_t *lock)
65{
66 MUTEX_DESTROY(&lock->mutex);
67 COND_DESTROY(&lock->cond);
68}
69
6d56dc1c 70void
71recursive_lock_release(pTHX_ recursive_lock_t *lock)
72{
73 MUTEX_LOCK(&lock->mutex);
74 if (lock->owner != aTHX) {
75 MUTEX_UNLOCK(&lock->mutex);
76 }
77 else {
78 if (--lock->locks == 0) {
79 lock->owner = NULL;
80 COND_SIGNAL(&lock->cond);
81 }
82 }
83 MUTEX_UNLOCK(&lock->mutex);
84}
a446a88f 85
6d56dc1c 86void
6b85e4fe 87recursive_lock_acquire(pTHX_ recursive_lock_t *lock,char *file,int line)
6d56dc1c 88{
89 assert(aTHX);
90 MUTEX_LOCK(&lock->mutex);
91 if (lock->owner == aTHX) {
92 lock->locks++;
93 }
94 else {
6b85e4fe 95 while (lock->owner) {
96#ifdef DEBUG_LOCKS
97 Perl_warn(aTHX_ " %p waiting - owned by %p %s:%d\n",
98 aTHX, lock->owner, lock->file, lock->line);
99#endif
6d56dc1c 100 COND_WAIT(&lock->cond,&lock->mutex);
6b85e4fe 101 }
6d56dc1c 102 lock->locks = 1;
103 lock->owner = aTHX;
6b85e4fe 104#ifdef DEBUG_LOCKS
105 lock->file = file;
106 lock->line = line;
107#endif
6d56dc1c 108 }
109 MUTEX_UNLOCK(&lock->mutex);
6b85e4fe 110 SAVEDESTRUCTOR_X(recursive_lock_release,lock);
6d56dc1c 111}
112
113#define ENTER_LOCK STMT_START { \
114 ENTER; \
6b85e4fe 115 recursive_lock_acquire(aTHX_ &PL_sharedsv_lock, __FILE__, __LINE__); \
a446a88f 116 } STMT_END
21312124 117
6d56dc1c 118#define LEAVE_LOCK LEAVE
119
21312124 120
121/* A common idiom is to acquire access and switch in ... */
122#define SHARED_EDIT STMT_START { \
6d56dc1c 123 ENTER_LOCK; \
21312124 124 SHARED_CONTEXT; \
125 } STMT_END
126
127/* then switch out and release access. */
128#define SHARED_RELEASE STMT_START { \
129 CALLER_CONTEXT; \
6d56dc1c 130 LEAVE_LOCK; \
21312124 131 } STMT_END
85e0a142 132
21312124 133
134/*
135
136 Shared SV
137
138 Shared SV is a structure for keeping the backend storage
139 of shared svs.
140
141 Shared-ness really only needs the SV * - the rest is for locks.
142 (Which suggests further space optimization ... )
143
144*/
68795e93 145
146typedef struct {
21312124 147 SV *sv; /* The actual SV - in shared space */
6d56dc1c 148 recursive_lock_t lock;
68795e93 149 perl_cond user_cond; /* For user-level conditions */
68795e93 150} shared_sv;
151
21312124 152/* The SV in shared-space has a back-pointer to the shared_sv
153 struct associated with it PERL_MAGIC_ext.
68795e93 154
21312124 155 The vtable used has just one entry - when the SV goes away
156 we free the memory for the above.
68795e93 157
21312124 158 */
68795e93 159
21312124 160int
161sharedsv_shared_mg_free(pTHX_ SV *sv, MAGIC *mg)
162{
163 shared_sv *shared = (shared_sv *) mg->mg_ptr;
6b85e4fe 164 assert( aTHX == PL_sharedsv_space );
21312124 165 if (shared) {
cab6ddb1 166 recursive_lock_destroy(aTHX_ &shared->lock);
579f9913 167 COND_DESTROY(&shared->user_cond);
21312124 168 PerlMemShared_free(shared);
169 mg->mg_ptr = NULL;
170 }
171 return 0;
172}
173
21312124 174MGVTBL sharedsv_shared_vtbl = {
175 0, /* get */
176 0, /* set */
177 0, /* len */
178 0, /* clear */
179 sharedsv_shared_mg_free, /* free */
180 0, /* copy */
181 0, /* dup */
182};
183
184/* Access to shared things is heavily based on MAGIC - in mg.h/mg.c/sv.c sense */
185
186/* In any thread that has access to a shared thing there is a "proxy"
187 for it in its own space which has 'MAGIC' associated which accesses
188 the shared thing.
189 */
190
191MGVTBL sharedsv_scalar_vtbl; /* scalars have this vtable */
192MGVTBL sharedsv_array_vtbl; /* hashes and arrays have this - like 'tie' */
193MGVTBL sharedsv_elem_vtbl; /* elements of hashes and arrays have this
194 _AS WELL AS_ the scalar magic */
195
196/* The sharedsv_elem_vtbl associates the element with the array/hash and
197 the sharedsv_scalar_vtbl associates it with the value
198 */
199
6b85e4fe 200
201/* Accessor to convert threads::shared::tie objects back shared_sv * */
202shared_sv *
203SV_to_sharedsv(pTHX_ SV *sv)
204{
205 shared_sv *shared = 0;
206 if (SvROK(sv))
207 {
208 shared = INT2PTR(shared_sv *, SvIV(SvRV(sv)));
209 }
210 return shared;
211}
212
21312124 213=for apidoc sharedsv_find
214
6b85e4fe 215Given a private side SV tries to find if the SV has a shared backend,
21312124 216by looking for the magic.
217
218=cut
219
220shared_sv *
221Perl_sharedsv_find(pTHX_ SV *sv)
222{
223 MAGIC *mg;
a446a88f 224 if (SvTYPE(sv) >= SVt_PVMG) {
225 switch(SvTYPE(sv)) {
226 case SVt_PVAV:
227 case SVt_PVHV:
228 if ((mg = mg_find(sv, PERL_MAGIC_tied))
229 && mg->mg_virtual == &sharedsv_array_vtbl) {
21312124 230 return (shared_sv *) mg->mg_ptr;
231 }
232 break;
a446a88f 233 default:
6b85e4fe 234 /* This should work for elements as well as they
235 * have scalar magic as well as their element magic
236 */
a446a88f 237 if ((mg = mg_find(sv, PERL_MAGIC_shared_scalar))
238 && mg->mg_virtual == &sharedsv_scalar_vtbl) {
21312124 239 return (shared_sv *) mg->mg_ptr;
6b85e4fe 240 }
a446a88f 241 break;
21312124 242 }
243 }
6b85e4fe 244 /* Just for tidyness of API also handle tie objects */
245 if (SvROK(sv) && sv_derived_from(sv, "threads::shared::tie")) {
246 return SV_to_sharedsv(aTHX_ sv);
247 }
21312124 248 return NULL;
249}
68795e93 250
251/*
21312124 252 * Almost all the pain is in this routine.
253 *
254 */
68795e93 255
21312124 256shared_sv *
257Perl_sharedsv_associate(pTHX_ SV **psv, SV *ssv, shared_sv *data)
258{
21312124 259 dTHXc;
a446a88f 260 MAGIC *mg = 0;
6b85e4fe 261 SV *sv = (psv) ? *psv : Nullsv;
a446a88f 262
263 /* If we are asked for an private ops we need a thread */
264 assert ( aTHX != PL_sharedsv_space );
265
266 /* To avoid need for recursive locks require caller to hold lock */
6d56dc1c 267 assert ( PL_sharedsv_lock.owner == aTHX );
6b85e4fe 268
269 /* First try and get existing global data structure */
68795e93 270
21312124 271 /* Try shared SV as 1st choice */
a446a88f 272 if (!data && ssv && SvTYPE(ssv) >= SVt_PVMG) {
436c6dd3 273 if( (mg = mg_find(ssv, PERL_MAGIC_ext)) ){
21312124 274 data = (shared_sv *) mg->mg_ptr;
275 }
276 }
6b85e4fe 277
278 /* Next see if private SV is associated with something */
279 if (!data && sv) {
280 data = Perl_sharedsv_find(aTHX_ sv);
21312124 281 }
6b85e4fe 282
21312124 283 /* If neither of those then create a new one */
284 if (!data) {
6b85e4fe 285 SHARED_CONTEXT;
b0cd0593 286 if (!ssv) {
6b85e4fe 287 ssv = newSV(0);
b0cd0593 288 SvREFCNT(ssv) = 0;
289 }
21312124 290 data = PerlMemShared_malloc(sizeof(shared_sv));
291 Zero(data,1,shared_sv);
6b85e4fe 292 SHAREDSvPTR(data) = ssv;
293 /* Tag shared side SV with data pointer */
294 sv_magicext(ssv, ssv, PERL_MAGIC_ext, &sharedsv_shared_vtbl,
295 (char *)data, 0);
6d56dc1c 296 recursive_lock_init(aTHX_ &data->lock);
21312124 297 COND_INIT(&data->user_cond);
6b85e4fe 298 CALLER_CONTEXT;
21312124 299 }
68795e93 300
21312124 301 if (!ssv)
302 ssv = SHAREDSvPTR(data);
6b85e4fe 303 if (!SHAREDSvPTR(data))
304 SHAREDSvPTR(data) = ssv;
305
306 /* If we know type upgrade shared side SV */
307 if (sv && SvTYPE(ssv) < SvTYPE(sv)) {
21312124 308 SHARED_CONTEXT;
21312124 309 sv_upgrade(ssv, SvTYPE(*psv));
21312124 310 CALLER_CONTEXT;
311 }
68795e93 312
21312124 313 /* Now if requested allocate private SV */
6b85e4fe 314 if (psv && !sv) {
315 *psv = sv = newSV(0);
21312124 316 }
317
318 /* Finally if private SV exists check and add magic */
6b85e4fe 319 if (sv) {
a446a88f 320 MAGIC *mg = 0;
6b85e4fe 321 if (SvTYPE(sv) < SvTYPE(ssv)) {
322 sv_upgrade(sv, SvTYPE(ssv));
323 }
21312124 324 switch(SvTYPE(sv)) {
325 case SVt_PVAV:
326 case SVt_PVHV:
327 if (!(mg = mg_find(sv, PERL_MAGIC_tied))
6b85e4fe 328 || mg->mg_virtual != &sharedsv_array_vtbl
329 || (shared_sv *) mg->mg_ptr != data) {
a446a88f 330 SV *obj = newSV(0);
331 sv_setref_iv(obj, "threads::shared::tie",PTR2IV(data));
6b85e4fe 332 if (mg) {
21312124 333 sv_unmagic(sv, PERL_MAGIC_tied);
6b85e4fe 334 }
a446a88f 335 mg = sv_magicext(sv, obj, PERL_MAGIC_tied, &sharedsv_array_vtbl,
21312124 336 (char *) data, 0);
337 mg->mg_flags |= (MGf_COPY|MGf_DUP);
6b85e4fe 338 SvREFCNT_inc(ssv);
a446a88f 339 SvREFCNT_dec(obj);
5c360ac5 340 if(SvOBJECT(ssv)) {
341 STRLEN len;
342 char* stash_ptr = SvPV((SV*) SvSTASH(ssv), len);
343 HV* stash = gv_stashpvn(stash_ptr, len, TRUE);
344 SvOBJECT_on(sv);
345 SvSTASH(sv) = (HV*)SvREFCNT_inc(stash);
346 }
21312124 347 }
348 break;
349
350 default:
6b85e4fe 351 if ((SvTYPE(sv) < SVt_PVMG)
352 || !(mg = mg_find(sv, PERL_MAGIC_shared_scalar))
353 || mg->mg_virtual != &sharedsv_scalar_vtbl
354 || (shared_sv *) mg->mg_ptr != data) {
355 if (mg) {
21312124 356 sv_unmagic(sv, PERL_MAGIC_shared_scalar);
6b85e4fe 357 }
21312124 358 mg = sv_magicext(sv, Nullsv, PERL_MAGIC_shared_scalar,
359 &sharedsv_scalar_vtbl, (char *)data, 0);
360 mg->mg_flags |= (MGf_COPY|MGf_DUP);
6b85e4fe 361 SvREFCNT_inc(ssv);
21312124 362 }
363 break;
364 }
6d56dc1c 365 assert ( Perl_sharedsv_find(aTHX_ *psv) == data );
21312124 366 }
21312124 367 return data;
368}
68795e93 369
370void
21312124 371Perl_sharedsv_free(pTHX_ shared_sv *shared)
68795e93 372{
21312124 373 if (shared) {
374 dTHXc;
375 SHARED_EDIT;
376 SvREFCNT_dec(SHAREDSvPTR(shared));
377 SHARED_RELEASE;
378 }
68795e93 379}
380
21312124 381void
382Perl_sharedsv_share(pTHX_ SV *sv)
383{
384 switch(SvTYPE(sv)) {
385 case SVt_PVGV:
386 Perl_croak(aTHX_ "Cannot share globs yet");
387 break;
388
389 case SVt_PVCV:
390 Perl_croak(aTHX_ "Cannot share subs yet");
391 break;
85e0a142 392
21312124 393 default:
6d56dc1c 394 ENTER_LOCK;
21312124 395 Perl_sharedsv_associate(aTHX_ &sv, 0, 0);
6d56dc1c 396 LEAVE_LOCK;
a446a88f 397 SvSETMAGIC(sv);
398 break;
21312124 399 }
400}
68795e93 401
21312124 402/* MAGIC (in mg.h sense) hooks */
68795e93 403
21312124 404int
405sharedsv_scalar_mg_get(pTHX_ SV *sv, MAGIC *mg)
68795e93 406{
21312124 407 shared_sv *shared = (shared_sv *) mg->mg_ptr;
6b85e4fe 408 assert(shared);
21312124 409
6d56dc1c 410 ENTER_LOCK;
21312124 411 if (SHAREDSvPTR(shared)) {
412 if (SvROK(SHAREDSvPTR(shared))) {
a446a88f 413 SV *obj = Nullsv;
414 Perl_sharedsv_associate(aTHX_ &obj, SvRV(SHAREDSvPTR(shared)), NULL);
415 sv_setsv_nomg(sv, &PL_sv_undef);
416 SvRV(sv) = obj;
417 SvROK_on(sv);
5c360ac5 418
21312124 419 }
420 else {
a446a88f 421 sv_setsv_nomg(sv, SHAREDSvPTR(shared));
21312124 422 }
423 }
6d56dc1c 424 LEAVE_LOCK;
21312124 425 return 0;
426}
427
6b85e4fe 428void
429sharedsv_scalar_store(pTHX_ SV *sv, shared_sv *shared)
21312124 430{
431 dTHXc;
21312124 432 bool allowed = TRUE;
21312124 433 if (SvROK(sv)) {
434 shared_sv* target = Perl_sharedsv_find(aTHX_ SvRV(sv));
435 if (target) {
a446a88f 436 SV *tmp;
437 SHARED_CONTEXT;
438 tmp = newRV(SHAREDSvPTR(target));
439 sv_setsv_nomg(SHAREDSvPTR(shared), tmp);
21312124 440 SvREFCNT_dec(tmp);
5c360ac5 441 if(SvOBJECT(SvRV(sv))) {
442 SV* fake_stash = newSVpv(HvNAME(SvSTASH(SvRV(sv))),0);
443 SvOBJECT_on(SHAREDSvPTR(target));
444 SvSTASH(SHAREDSvPTR(target)) = (HV*)fake_stash;
445 }
a446a88f 446 CALLER_CONTEXT;
21312124 447 }
448 else {
449 allowed = FALSE;
450 }
451 }
452 else {
5c360ac5 453 SvTEMP_off(sv);
a446a88f 454 SHARED_CONTEXT;
455 sv_setsv_nomg(SHAREDSvPTR(shared), sv);
5c360ac5 456 if(SvOBJECT(sv)) {
457 SV* fake_stash = newSVpv(HvNAME(SvSTASH(sv)),0);
458 SvOBJECT_on(SHAREDSvPTR(shared));
459 SvSTASH(SHAREDSvPTR(shared)) = (HV*)fake_stash;
460 }
a446a88f 461 CALLER_CONTEXT;
21312124 462 }
21312124 463 if (!allowed) {
464 Perl_croak(aTHX_ "Invalid value for shared scalar");
465 }
6b85e4fe 466}
467
468int
469sharedsv_scalar_mg_set(pTHX_ SV *sv, MAGIC *mg)
470{
471 shared_sv *shared;
472 ENTER_LOCK;
473 /* We call associate to potentially upgrade shared side SV */
474 shared = Perl_sharedsv_associate(aTHX_ &sv, Nullsv, (shared_sv *) mg->mg_ptr);
475 assert(shared);
476 sharedsv_scalar_store(aTHX_ sv, shared);
477 LEAVE_LOCK;
21312124 478 return 0;
68795e93 479}
480
21312124 481int
482sharedsv_scalar_mg_free(pTHX_ SV *sv, MAGIC *mg)
483{
a446a88f 484 shared_sv *shared = (shared_sv *) mg->mg_ptr;
eb31b78e 485#if 0
a446a88f 486 assert (SvREFCNT(SHAREDSvPTR(shared)) < 1000);
eb31b78e 487#endif
a446a88f 488 Perl_sharedsv_free(aTHX_ shared);
489 return 0;
490}
491
492int
493sharedsv_scalar_mg_clear(pTHX_ SV *sv, MAGIC *mg)
494{
21312124 495 return 0;
496}
68795e93 497
498/*
21312124 499 * Called during cloning of new threads
500 */
501int
502sharedsv_scalar_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *param)
503{
504 shared_sv *shared = (shared_sv *) mg->mg_ptr;
505 if (shared) {
506 SvREFCNT_inc(SHAREDSvPTR(shared));
507 }
508 return 0;
509}
68795e93 510
21312124 511MGVTBL sharedsv_scalar_vtbl = {
512 sharedsv_scalar_mg_get, /* get */
513 sharedsv_scalar_mg_set, /* set */
514 0, /* len */
a446a88f 515 sharedsv_scalar_mg_clear, /* clear */
21312124 516 sharedsv_scalar_mg_free, /* free */
517 0, /* copy */
518 sharedsv_scalar_mg_dup /* dup */
519};
68795e93 520
21312124 521/* Now the arrays/hashes stuff */
21312124 522int
523sharedsv_elem_mg_FETCH(pTHX_ SV *sv, MAGIC *mg)
68795e93 524{
21312124 525 dTHXc;
6b85e4fe 526 shared_sv *shared = SV_to_sharedsv(aTHX_ mg->mg_obj);
21312124 527 shared_sv *target = Perl_sharedsv_find(aTHX_ sv);
528 SV** svp;
529
a446a88f 530 assert ( shared );
531 assert ( SHAREDSvPTR(shared) );
532
6b85e4fe 533 ENTER_LOCK;
21312124 534 if (SvTYPE(SHAREDSvPTR(shared)) == SVt_PVAV) {
a446a88f 535 assert ( mg->mg_ptr == 0 );
6b85e4fe 536 SHARED_CONTEXT;
a446a88f 537 svp = av_fetch((AV*) SHAREDSvPTR(shared), mg->mg_len, 0);
21312124 538 }
539 else {
6b85e4fe 540 char *key = mg->mg_ptr;
541 STRLEN len = mg->mg_len;
a446a88f 542 assert ( mg->mg_ptr != 0 );
6b85e4fe 543 if (mg->mg_len == HEf_SVKEY) {
544 key = SvPV((SV *) mg->mg_ptr, len);
545 }
546 SHARED_CONTEXT;
547 svp = hv_fetch((HV*) SHAREDSvPTR(shared), key, len, 0);
21312124 548 }
6b85e4fe 549 CALLER_CONTEXT;
21312124 550 if (svp) {
6b85e4fe 551 /* Exists in the array */
552 target = Perl_sharedsv_associate(aTHX_ &sv, *svp, target);
553 sv_setsv(sv, *svp);
21312124 554 }
6b85e4fe 555 else {
556 /* Not in the array */
557 sv_setsv(sv, &PL_sv_undef);
68795e93 558 }
6b85e4fe 559 LEAVE_LOCK;
21312124 560 return 0;
68795e93 561}
562
21312124 563int
564sharedsv_elem_mg_STORE(pTHX_ SV *sv, MAGIC *mg)
565{
566 dTHXc;
6b85e4fe 567 shared_sv *shared = SV_to_sharedsv(aTHX_ mg->mg_obj);
a446a88f 568 shared_sv *target;
6b85e4fe 569 SV **svp;
21312124 570 /* Theory - SV itself is magically shared - and we have ordered the
571 magic such that by the time we get here it has been stored
572 to its shared counterpart
573 */
6d56dc1c 574 ENTER_LOCK;
575 assert(shared);
576 assert(SHAREDSvPTR(shared));
21312124 577 if (SvTYPE(SHAREDSvPTR(shared)) == SVt_PVAV) {
6b85e4fe 578 assert ( mg->mg_ptr == 0 );
579 SHARED_CONTEXT;
580 svp = av_fetch((AV*) SHAREDSvPTR(shared), mg->mg_len, 1);
21312124 581 }
582 else {
6b85e4fe 583 char *key = mg->mg_ptr;
584 STRLEN len = mg->mg_len;
585 assert ( mg->mg_ptr != 0 );
586 if (mg->mg_len == HEf_SVKEY)
587 key = SvPV((SV *) mg->mg_ptr, len);
588 SHARED_CONTEXT;
589 svp = hv_fetch((HV*) SHAREDSvPTR(shared), key, len, 1);
21312124 590 }
6b85e4fe 591 CALLER_CONTEXT;
592 target = Perl_sharedsv_associate(aTHX_ &sv, *svp, 0);
593 sharedsv_scalar_store(aTHX_ sv, target);
594 LEAVE_LOCK;
21312124 595 return 0;
596}
68795e93 597
21312124 598int
599sharedsv_elem_mg_DELETE(pTHX_ SV *sv, MAGIC *mg)
68795e93 600{
21312124 601 dTHXc;
6b85e4fe 602 shared_sv *shared = SV_to_sharedsv(aTHX_ mg->mg_obj);
6b85e4fe 603 ENTER_LOCK;
604 sharedsv_elem_mg_FETCH(aTHX_ sv, mg);
21312124 605 if (SvTYPE(SHAREDSvPTR(shared)) == SVt_PVAV) {
6b85e4fe 606 SHARED_CONTEXT;
607 av_delete((AV*) SHAREDSvPTR(shared), mg->mg_len, G_DISCARD);
68795e93 608 }
21312124 609 else {
6b85e4fe 610 char *key = mg->mg_ptr;
611 STRLEN len = mg->mg_len;
612 assert ( mg->mg_ptr != 0 );
613 if (mg->mg_len == HEf_SVKEY)
614 key = SvPV((SV *) mg->mg_ptr, len);
615 SHARED_CONTEXT;
616 hv_delete((HV*) SHAREDSvPTR(shared), key, len, G_DISCARD);
21312124 617 }
6b85e4fe 618 CALLER_CONTEXT;
619 LEAVE_LOCK;
21312124 620 return 0;
621}
622
21312124 623int
624sharedsv_elem_mg_free(pTHX_ SV *sv, MAGIC *mg)
625{
6b85e4fe 626 Perl_sharedsv_free(aTHX_ SV_to_sharedsv(aTHX_ mg->mg_obj));
21312124 627 return 0;
628}
629
630int
631sharedsv_elem_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *param)
632{
6b85e4fe 633 shared_sv *shared = SV_to_sharedsv(aTHX_ mg->mg_obj);
21312124 634 SvREFCNT_inc(SHAREDSvPTR(shared));
635 mg->mg_flags |= MGf_DUP;
636 return 0;
637}
638
639MGVTBL sharedsv_elem_vtbl = {
640 sharedsv_elem_mg_FETCH, /* get */
641 sharedsv_elem_mg_STORE, /* set */
642 0, /* len */
643 sharedsv_elem_mg_DELETE, /* clear */
644 sharedsv_elem_mg_free, /* free */
645 0, /* copy */
646 sharedsv_elem_mg_dup /* dup */
647};
648
649U32
650sharedsv_array_mg_FETCHSIZE(pTHX_ SV *sv, MAGIC *mg)
651{
652 dTHXc;
653 shared_sv *shared = (shared_sv *) mg->mg_ptr;
654 U32 val;
655 SHARED_EDIT;
656 if (SvTYPE(SHAREDSvPTR(shared)) == SVt_PVAV) {
657 val = av_len((AV*) SHAREDSvPTR(shared));
658 }
659 else {
660 /* not actually defined by tie API but ... */
661 val = HvKEYS((HV*) SHAREDSvPTR(shared));
662 }
663 SHARED_RELEASE;
664 return val;
665}
666
667int
668sharedsv_array_mg_CLEAR(pTHX_ SV *sv, MAGIC *mg)
669{
670 dTHXc;
671 shared_sv *shared = (shared_sv *) mg->mg_ptr;
672 SHARED_EDIT;
673 if (SvTYPE(SHAREDSvPTR(shared)) == SVt_PVAV) {
674 av_clear((AV*) SHAREDSvPTR(shared));
675 }
676 else {
677 hv_clear((HV*) SHAREDSvPTR(shared));
678 }
679 SHARED_RELEASE;
680 return 0;
681}
682
683int
684sharedsv_array_mg_free(pTHX_ SV *sv, MAGIC *mg)
685{
686 Perl_sharedsv_free(aTHX_ (shared_sv *) mg->mg_ptr);
687 return 0;
68795e93 688}
689
690/*
21312124 691 * This is called when perl is about to access an element of
692 * the array -
693 */
694int
695sharedsv_array_mg_copy(pTHX_ SV *sv, MAGIC* mg,
696 SV *nsv, const char *name, int namlen)
697{
698 shared_sv *shared = (shared_sv *) mg->mg_ptr;
699 MAGIC *nmg = sv_magicext(nsv,mg->mg_obj,
700 toLOWER(mg->mg_type),&sharedsv_elem_vtbl,
701 name, namlen);
b747d46a 702 ENTER_LOCK;
a446a88f 703 SvREFCNT_inc(SHAREDSvPTR(shared));
b747d46a 704 LEAVE_LOCK;
21312124 705 nmg->mg_flags |= MGf_DUP;
21312124 706 return 1;
707}
708
709int
710sharedsv_array_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *param)
711{
712 shared_sv *shared = (shared_sv *) mg->mg_ptr;
713 SvREFCNT_inc(SHAREDSvPTR(shared));
714 mg->mg_flags |= MGf_DUP;
715 return 0;
716}
717
718MGVTBL sharedsv_array_vtbl = {
719 0, /* get */
720 0, /* set */
721 sharedsv_array_mg_FETCHSIZE, /* len */
722 sharedsv_array_mg_CLEAR, /* clear */
723 sharedsv_array_mg_free, /* free */
724 sharedsv_array_mg_copy, /* copy */
725 sharedsv_array_mg_dup /* dup */
726};
727
728=for apidoc sharedsv_unlock
68795e93 729
730Recursively unlocks a shared sv.
731
21312124 732=cut
68795e93 733
734void
735Perl_sharedsv_unlock(pTHX_ shared_sv* ssv)
736{
6d56dc1c 737 recursive_lock_release(aTHX_ &ssv->lock);
68795e93 738}
739
21312124 740=for apidoc sharedsv_lock
68795e93 741
21312124 742Recursive locks on a sharedsv.
743Locks are dynamically scoped at the level of the first lock.
68795e93 744
21312124 745=cut
68795e93 746
747void
21312124 748Perl_sharedsv_lock(pTHX_ shared_sv* ssv)
68795e93 749{
21312124 750 if (!ssv)
751 return;
6b85e4fe 752 recursive_lock_acquire(aTHX_ &ssv->lock, __FILE__, __LINE__);
68795e93 753}
754
afe38520 755/* handles calls from lock() builtin via PL_lockhook */
756
21312124 757void
758Perl_sharedsv_locksv(pTHX_ SV *sv)
759{
afe38520 760 shared_sv* shared;
761
762 if(SvROK(sv))
763 sv = SvRV(sv);
38875929 764 shared = Perl_sharedsv_find(aTHX_ sv);
afe38520 765 if(!shared)
766 croak("lock can only be used on shared values");
767 Perl_sharedsv_lock(aTHX_ shared);
b050c948 768}
769
21312124 770=head1 Shared SV Functions
b050c948 771
21312124 772=for apidoc sharedsv_init
b050c948 773
21312124 774Saves a space for keeping SVs wider than an interpreter,
b050c948 775
21312124 776=cut
777
778void
779Perl_sharedsv_init(pTHX)
780{
781 dTHXc;
782 /* This pair leaves us in shared context ... */
783 PL_sharedsv_space = perl_alloc();
784 perl_construct(PL_sharedsv_space);
785 CALLER_CONTEXT;
6d56dc1c 786 recursive_lock_init(aTHX_ &PL_sharedsv_lock);
21312124 787 PL_lockhook = &Perl_sharedsv_locksv;
788 PL_sharehook = &Perl_sharedsv_share;
b050c948 789}
790
73e09c8f 791#endif /* USE_ITHREADS */
792
21312124 793MODULE = threads::shared PACKAGE = threads::shared::tie
b050c948 794
21312124 795PROTOTYPES: DISABLE
b050c948 796
73e09c8f 797#ifdef USE_ITHREADS
6b85e4fe 798
21312124 799void
800PUSH(shared_sv *shared, ...)
801CODE:
802 dTHXc;
803 int i;
21312124 804 for(i = 1; i < items; i++) {
805 SV* tmp = newSVsv(ST(i));
a446a88f 806 shared_sv *target;
6d56dc1c 807 ENTER_LOCK;
a446a88f 808 target = Perl_sharedsv_associate(aTHX_ &tmp, Nullsv, 0);
6b85e4fe 809 sharedsv_scalar_store(aTHX_ tmp, target);
21312124 810 SHARED_CONTEXT;
811 av_push((AV*) SHAREDSvPTR(shared), SHAREDSvPTR(target));
b0cd0593 812 SvREFCNT_inc(SHAREDSvPTR(target));
a446a88f 813 SHARED_RELEASE;
21312124 814 SvREFCNT_dec(tmp);
815 }
b050c948 816
21312124 817void
818UNSHIFT(shared_sv *shared, ...)
819CODE:
820 dTHXc;
821 int i;
6d56dc1c 822 ENTER_LOCK;
21312124 823 SHARED_CONTEXT;
824 av_unshift((AV*)SHAREDSvPTR(shared), items - 1);
825 CALLER_CONTEXT;
826 for(i = 1; i < items; i++) {
827 SV* tmp = newSVsv(ST(i));
828 shared_sv *target = Perl_sharedsv_associate(aTHX_ &tmp, Nullsv, 0);
6b85e4fe 829 sharedsv_scalar_store(aTHX_ tmp, target);
21312124 830 SHARED_CONTEXT;
831 av_store((AV*) SHAREDSvPTR(shared), i - 1, SHAREDSvPTR(target));
b0cd0593 832 SvREFCNT_inc(SHAREDSvPTR(target));
21312124 833 CALLER_CONTEXT;
834 SvREFCNT_dec(tmp);
835 }
6d56dc1c 836 LEAVE_LOCK;
b050c948 837
21312124 838void
839POP(shared_sv *shared)
840CODE:
841 dTHXc;
842 SV* sv;
6d56dc1c 843 ENTER_LOCK;
21312124 844 SHARED_CONTEXT;
845 sv = av_pop((AV*)SHAREDSvPTR(shared));
846 CALLER_CONTEXT;
9b018978 847 ST(0) = sv_newmortal();
21312124 848 Perl_sharedsv_associate(aTHX_ &ST(0), sv, 0);
9b018978 849 SvREFCNT_dec(sv);
6d56dc1c 850 LEAVE_LOCK;
21312124 851 XSRETURN(1);
b050c948 852
21312124 853void
854SHIFT(shared_sv *shared)
855CODE:
856 dTHXc;
857 SV* sv;
6d56dc1c 858 ENTER_LOCK;
21312124 859 SHARED_CONTEXT;
860 sv = av_shift((AV*)SHAREDSvPTR(shared));
861 CALLER_CONTEXT;
9b018978 862 ST(0) = sv_newmortal();
21312124 863 Perl_sharedsv_associate(aTHX_ &ST(0), sv, 0);
9b018978 864 SvREFCNT_dec(sv);
6d56dc1c 865 LEAVE_LOCK;
21312124 866 XSRETURN(1);
b050c948 867
21312124 868void
869EXTEND(shared_sv *shared, IV count)
870CODE:
871 dTHXc;
872 SHARED_EDIT;
873 av_extend((AV*)SHAREDSvPTR(shared), count);
874 SHARED_RELEASE;
b050c948 875
21312124 876void
6b85e4fe 877STORESIZE(shared_sv *shared,IV count)
878CODE:
879 dTHXc;
880 SHARED_EDIT;
881 av_fill((AV*) SHAREDSvPTR(shared), count);
882 SHARED_RELEASE;
883
884
885
886
887void
21312124 888EXISTS(shared_sv *shared, SV *index)
889CODE:
890 dTHXc;
891 bool exists;
892 SHARED_EDIT;
893 if (SvTYPE(SHAREDSvPTR(shared)) == SVt_PVAV) {
894 exists = av_exists((AV*) SHAREDSvPTR(shared), SvIV(index));
895 }
896 else {
6b85e4fe 897 STRLEN len;
898 char *key = SvPV(index,len);
899 exists = hv_exists((HV*) SHAREDSvPTR(shared), key, len);
21312124 900 }
901 SHARED_RELEASE;
902 ST(0) = (exists) ? &PL_sv_yes : &PL_sv_no;
903 XSRETURN(1);
b050c948 904
905
906void
21312124 907FIRSTKEY(shared_sv *shared)
908CODE:
909 dTHXc;
910 char* key = NULL;
911 I32 len = 0;
912 HE* entry;
6d56dc1c 913 ENTER_LOCK;
21312124 914 SHARED_CONTEXT;
915 hv_iterinit((HV*) SHAREDSvPTR(shared));
916 entry = hv_iternext((HV*) SHAREDSvPTR(shared));
917 if (entry) {
918 key = hv_iterkey(entry,&len);
919 CALLER_CONTEXT;
920 ST(0) = sv_2mortal(newSVpv(key, len));
921 } else {
922 CALLER_CONTEXT;
923 ST(0) = &PL_sv_undef;
924 }
6d56dc1c 925 LEAVE_LOCK;
21312124 926 XSRETURN(1);
b050c948 927
866fba46 928void
21312124 929NEXTKEY(shared_sv *shared, SV *oldkey)
930CODE:
931 dTHXc;
932 char* key = NULL;
933 I32 len = 0;
934 HE* entry;
6d56dc1c 935 ENTER_LOCK;
21312124 936 SHARED_CONTEXT;
937 entry = hv_iternext((HV*) SHAREDSvPTR(shared));
6b85e4fe 938 if (entry) {
21312124 939 key = hv_iterkey(entry,&len);
940 CALLER_CONTEXT;
941 ST(0) = sv_2mortal(newSVpv(key, len));
942 } else {
943 CALLER_CONTEXT;
944 ST(0) = &PL_sv_undef;
945 }
6d56dc1c 946 LEAVE_LOCK;
21312124 947 XSRETURN(1);
948
949MODULE = threads::shared PACKAGE = threads::shared
950
951PROTOTYPES: ENABLE
866fba46 952
68795e93 953void
9c4972d9 954_id(SV *ref)
955 PROTOTYPE: \[$@%]
956CODE:
957 shared_sv *shared;
afe38520 958 ref = SvRV(ref);
9c4972d9 959 if(SvROK(ref))
960 ref = SvRV(ref);
436c6dd3 961 if( (shared = Perl_sharedsv_find(aTHX_ ref)) ){
9c4972d9 962 ST(0) = sv_2mortal(newSViv(PTR2IV(shared)));
963 XSRETURN(1);
964 }
965 XSRETURN_UNDEF;
966
967
968void
6b85e4fe 969_refcnt(SV *ref)
a446a88f 970 PROTOTYPE: \[$@%]
971CODE:
972 shared_sv *shared;
afe38520 973 ref = SvRV(ref);
a446a88f 974 if(SvROK(ref))
975 ref = SvRV(ref);
436c6dd3 976 if( (shared = Perl_sharedsv_find(aTHX_ ref)) ){
a446a88f 977 if (SHAREDSvPTR(shared)) {
978 ST(0) = sv_2mortal(newSViv(SvREFCNT(SHAREDSvPTR(shared))));
979 XSRETURN(1);
980 }
981 else {
436c6dd3 982 Perl_warn(aTHX_ "%" SVf " s=%p has no shared SV",ST(0),shared);
a446a88f 983 }
984 }
985 else {
436c6dd3 986 Perl_warn(aTHX_ "%" SVf " is not shared",ST(0));
a446a88f 987 }
988 XSRETURN_UNDEF;
989
caf25f3b 990SV*
a446a88f 991share(SV *ref)
992 PROTOTYPE: \[$@%]
993 CODE:
56fcff86 994 if(!SvROK(ref))
995 Perl_croak(aTHX_ "Argument to share needs to be passed as ref");
afe38520 996 ref = SvRV(ref);
a446a88f 997 if(SvROK(ref))
998 ref = SvRV(ref);
38875929 999 Perl_sharedsv_share(aTHX_ ref);
caf25f3b 1000 RETVAL = newRV(ref);
1001 OUTPUT:
1002 RETVAL
a446a88f 1003
1004void
21312124 1005lock_enabled(SV *ref)
ce127893 1006 PROTOTYPE: \[$@%]
6f942b98 1007 CODE:
1008 shared_sv* shared;
56fcff86 1009 if(!SvROK(ref))
1010 Perl_croak(aTHX_ "Argument to lock needs to be passed as ref");
afe38520 1011 ref = SvRV(ref);
6f942b98 1012 if(SvROK(ref))
1013 ref = SvRV(ref);
38875929 1014 shared = Perl_sharedsv_find(aTHX_ ref);
21312124 1015 if(!shared)
1016 croak("lock can only be used on shared values");
1017 Perl_sharedsv_lock(aTHX_ shared);
6f942b98 1018
1019void
21312124 1020cond_wait_enabled(SV *ref)
ce127893 1021 PROTOTYPE: \[$@%]
6f942b98 1022 CODE:
1023 shared_sv* shared;
1024 int locks;
56fcff86 1025 if(!SvROK(ref))
1026 Perl_croak(aTHX_ "Argument to cond_wait needs to be passed as ref");
afe38520 1027 ref = SvRV(ref);
6f942b98 1028 if(SvROK(ref))
1029 ref = SvRV(ref);
1030 shared = Perl_sharedsv_find(aTHX_ ref);
1031 if(!shared)
1032 croak("cond_wait can only be used on shared values");
6d56dc1c 1033 if(shared->lock.owner != aTHX)
6f942b98 1034 croak("You need a lock before you can cond_wait");
6d56dc1c 1035 /* Stealing the members of the lock object worries me - NI-S */
1036 MUTEX_LOCK(&shared->lock.mutex);
1037 shared->lock.owner = NULL;
39f33d92 1038 locks = shared->lock.locks;
1039 shared->lock.locks = 0;
89661126 1040
1041 /* since we are releasing the lock here we need to tell other
1042 people that is ok to go ahead and use it */
1043 COND_SIGNAL(&shared->lock.cond);
6d56dc1c 1044 COND_WAIT(&shared->user_cond, &shared->lock.mutex);
89661126 1045 while(shared->lock.owner != NULL) {
1046 COND_WAIT(&shared->lock.cond,&shared->lock.mutex);
1047 }
6d56dc1c 1048 shared->lock.owner = aTHX;
1049 shared->lock.locks = locks;
1050 MUTEX_UNLOCK(&shared->lock.mutex);
6f942b98 1051
21312124 1052void
1053cond_signal_enabled(SV *ref)
ce127893 1054 PROTOTYPE: \[$@%]
6f942b98 1055 CODE:
1056 shared_sv* shared;
56fcff86 1057 if(!SvROK(ref))
1058 Perl_croak(aTHX_ "Argument to cond_signal needs to be passed as ref");
afe38520 1059 ref = SvRV(ref);
6f942b98 1060 if(SvROK(ref))
1061 ref = SvRV(ref);
1062 shared = Perl_sharedsv_find(aTHX_ ref);
38875929 1063 if (ckWARN(WARN_THREADS) && shared->lock.owner != aTHX)
1064 Perl_warner(aTHX_ packWARN(WARN_THREADS),
1065 "cond_signal() called on unlocked variable");
6f942b98 1066 if(!shared)
1067 croak("cond_signal can only be used on shared values");
1068 COND_SIGNAL(&shared->user_cond);
1069
21312124 1070void
1071cond_broadcast_enabled(SV *ref)
ce127893 1072 PROTOTYPE: \[$@%]
6f942b98 1073 CODE:
1074 shared_sv* shared;
56fcff86 1075 if(!SvROK(ref))
1076 Perl_croak(aTHX_ "Argument to cond_broadcast needs to be passed as ref");
afe38520 1077 ref = SvRV(ref);
6f942b98 1078 if(SvROK(ref))
1079 ref = SvRV(ref);
1080 shared = Perl_sharedsv_find(aTHX_ ref);
1081 if(!shared)
1082 croak("cond_broadcast can only be used on shared values");
38875929 1083 if (ckWARN(WARN_THREADS) && shared->lock.owner != aTHX)
1084 Perl_warner(aTHX_ packWARN(WARN_THREADS),
1085 "cond_broadcast() called on unlocked variable");
6f942b98 1086 COND_BROADCAST(&shared->user_cond);
b050c948 1087
5c360ac5 1088
1089SV*
1090bless(SV* ref, ...);
1091 PROTOTYPE: $;$
1092 CODE:
1093 {
1094 HV* stash;
1095 shared_sv* shared;
1096 if (items == 1)
1097 stash = CopSTASH(PL_curcop);
1098 else {
1099 SV* ssv = ST(1);
1100 STRLEN len;
1101 char *ptr;
1102
1103 if (ssv && !SvGMAGICAL(ssv) && !SvAMAGIC(ssv) && SvROK(ssv))
1104 Perl_croak(aTHX_ "Attempt to bless into a reference");
1105 ptr = SvPV(ssv,len);
1106 if (ckWARN(WARN_MISC) && len == 0)
1107 Perl_warner(aTHX_ packWARN(WARN_MISC),
1108 "Explicit blessing to '' (assuming package main)");
1109 stash = gv_stashpvn(ptr, len, TRUE);
1110 }
1111 SvREFCNT_inc(ref);
1112 (void)sv_bless(ref, stash);
1113 RETVAL = ref;
1114 shared = Perl_sharedsv_find(aTHX_ ref);
1115 if(shared) {
1116 dTHXc;
1117 ENTER_LOCK;
1118 SHARED_CONTEXT;
1119 {
1120 SV* fake_stash = newSVpv(HvNAME(stash),0);
1121 (void)sv_bless(SHAREDSvPTR(shared),(HV*)fake_stash);
1122 }
1123 CALLER_CONTEXT;
1124 LEAVE_LOCK;
1125 }
1126 }
1127 OUTPUT:
1128 RETVAL
1129
73e09c8f 1130#endif /* USE_ITHREADS */
1131
68795e93 1132BOOT:
1133{
73e09c8f 1134#ifdef USE_ITHREADS
68795e93 1135 Perl_sharedsv_init(aTHX);
73e09c8f 1136#endif /* USE_ITHREADS */
68795e93 1137}
73e09c8f 1138
1139
1140