Beginings of PerlIO_dup support (unstable)
[p5sagit/p5-mst-13.2.git] / sharedsv.c
1 /*    sharedsv.c
2  *
3  *    Copyright (c) 2001, Larry Wall
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  *
8  */
9
10 /*
11 * Contributed by Arthur Bergman arthur@contiller.se
12 *
13 * "Hand any two wizards a piece of rope and they would instinctively pull in
14 * opposite directions."
15 *                         --Sourcery
16 *
17 */
18
19 #include "EXTERN.h"
20 #define PERL_IN_SHAREDSV_C
21 #include "perl.h"
22
23 #ifdef USE_ITHREADS
24
25
26
27 /*
28   Shared SV
29
30   Shared SV is a structure for keeping the backend storage
31   of shared svs.
32
33  */
34
35 /*
36 =for apidoc sharedsv_init
37
38 Saves a space for keeping SVs wider than an interpreter,
39 currently only stores a pointer to the first interpreter.
40
41 =cut
42 */
43
44 void
45 Perl_sharedsv_init(pTHX)
46 {
47   PerlInterpreter* old_context = PERL_GET_CONTEXT;
48   PL_sharedsv_space = perl_alloc();
49   perl_construct(PL_sharedsv_space);
50   PERL_SET_CONTEXT(old_context);
51   MUTEX_INIT(&PL_sharedsv_space_mutex);
52 }
53
54 /*
55 =for apidoc sharedsv_new
56
57 Allocates a new shared sv struct, you must yourself create the SV/AV/HV.
58 =cut
59 */
60
61 shared_sv *
62 Perl_sharedsv_new(pTHX)
63 {
64     shared_sv* ssv;
65     New(2555,ssv,1,shared_sv);
66     MUTEX_INIT(&ssv->mutex);
67     COND_INIT(&ssv->cond);
68     COND_INIT(&ssv->user_cond);
69     ssv->owner = 0;
70     ssv->locks = 0;
71     return ssv;
72 }
73
74
75 /*
76 =for apidoc sharedsv_find
77
78 Tries to find if a given SV has a shared backend, either by
79 looking at magic, or by checking if it is tied again threads::shared.
80
81 =cut
82 */
83
84 shared_sv *
85 Perl_sharedsv_find(pTHX_ SV* sv)
86 {
87     /* does all it can to find a shared_sv struct, returns NULL otherwise */
88     shared_sv* ssv = NULL;
89     return ssv;
90 }
91
92 /*
93 =for apidoc sharedsv_lock
94
95 Recursive locks on a sharedsv.
96 Locks are dynamicly scoped at the level of the first lock.
97 =cut
98 */
99 void
100 Perl_sharedsv_lock(pTHX_ shared_sv* ssv)
101 {
102     if(!ssv)
103         return;
104     MUTEX_LOCK(&ssv->mutex);
105     if(ssv->owner && ssv->owner == my_perl) {
106         ssv->locks++;
107         MUTEX_UNLOCK(&ssv->mutex);
108         return;
109     }
110     while(ssv->owner) 
111       COND_WAIT(&ssv->cond,&ssv->mutex);
112     ssv->locks++;
113     ssv->owner = my_perl;
114     if(ssv->locks == 1)
115         SAVEDESTRUCTOR_X(Perl_sharedsv_unlock_scope,ssv);
116     MUTEX_UNLOCK(&ssv->mutex);
117 }
118
119 /*
120 =for apidoc sharedsv_unlock
121
122 Recursively unlocks a shared sv.
123
124 =cut
125 */
126
127 void
128 Perl_sharedsv_unlock(pTHX_ shared_sv* ssv)
129 {
130     MUTEX_LOCK(&ssv->mutex);
131     if(ssv->owner != my_perl) {
132         Perl_croak(aTHX_ "panic: Perl_sharedsv_unlock unlocking mutex that we don't own");
133         MUTEX_UNLOCK(&ssv->mutex); 
134         return;
135     } 
136
137     if(--ssv->locks == 0) {
138         ssv->owner = NULL;
139         COND_SIGNAL(&ssv->cond);
140     }
141     MUTEX_UNLOCK(&ssv->mutex);
142  }
143
144 void
145 Perl_sharedsv_unlock_scope(pTHX_ shared_sv* ssv)
146 {
147     MUTEX_LOCK(&ssv->mutex);
148     if(ssv->owner != my_perl) {
149         MUTEX_UNLOCK(&ssv->mutex);
150         return;
151     }
152     ssv->locks = 0;
153     ssv->owner = NULL;
154     COND_SIGNAL(&ssv->cond);
155     MUTEX_UNLOCK(&ssv->mutex);
156 }
157
158 /*
159 =for apidoc sharedsv_thrcnt_inc
160
161 Increments the threadcount of a sharedsv.
162 =cut
163 */
164 void
165 Perl_sharedsv_thrcnt_inc(pTHX_ shared_sv* ssv)
166 {
167   SHAREDSvEDIT(ssv);
168   SvREFCNT_inc(ssv->sv);
169   SHAREDSvRELEASE(ssv);
170 }
171
172 /*
173 =for apidoc sharedsv_thrcnt_dec
174
175 Decrements the threadcount of a shared sv. When a threads frontend is freed
176 this function should be called.
177
178 =cut
179 */
180
181 void
182 Perl_sharedsv_thrcnt_dec(pTHX_ shared_sv* ssv)
183 {
184     SV* sv;
185     SHAREDSvEDIT(ssv);
186     sv = SHAREDSvGET(ssv);
187     if (SvREFCNT(sv) == 1) {
188         switch (SvTYPE(sv)) {
189         case SVt_RV:
190             if (SvROK(sv))
191             Perl_sharedsv_thrcnt_dec(aTHX_ INT2PTR(shared_sv *, SvIV(SvRV(sv))));
192             break;
193         case SVt_PVAV: {
194             SV **src_ary  = AvARRAY((AV *)sv);
195             SSize_t items = AvFILLp((AV *)sv) + 1;
196
197             while (items-- > 0) {
198             if(SvTYPE(*src_ary))
199                 Perl_sharedsv_thrcnt_dec(aTHX_ INT2PTR(shared_sv *, SvIV(*src_ary++)));
200             }
201             break;
202         }
203         case SVt_PVHV: {
204             HE *entry;
205             (void)hv_iterinit((HV *)sv);
206             while ((entry = hv_iternext((HV *)sv)))
207                 Perl_sharedsv_thrcnt_dec(
208                     aTHX_ INT2PTR(shared_sv *, SvIV(hv_iterval((HV *)sv, entry)))
209                 );
210             break;
211         }
212         }
213     }
214     SvREFCNT_dec(sv);
215     SHAREDSvRELEASE(ssv);
216 }
217
218 #endif /* USE_ITHREADS */
219