From: Dave Mitchell <davem@fdisolutions.com>
Date: Thu, 29 Dec 2005 12:00:29 +0000 (+0000)
Subject: re-implement MY_CXT API more efficiently, and add explicit
X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=f16dd614412ea67a8eb64bb09a88fccdbd9db6b6;p=p5sagit%2Fp5-mst-13.2.git

re-implement MY_CXT API more efficiently, and add explicit
interpeter arg variant

p4raw-id: //depot/perl@26523
---

diff --git a/embed.fnc b/embed.fnc
index 46d12a2..5aed31e 100644
--- a/embed.fnc
+++ b/embed.fnc
@@ -1609,6 +1609,11 @@ Apnod	|int	|my_sprintf	|NN char *buffer|NN const char *pat|...
 
 px	|void	|my_clearenv
 
+#ifdef PERL_IMPLICIT_CONTEXT
+po	|void*	|my_cxt_init	|NN int *index|size_t size
+#endif
+
+
 END_EXTERN_C
 /*
  * ex: set ts=8 sts=4 sw=4 noet:
diff --git a/embed.h b/embed.h
index c0e3b52..6e831a0 100644
--- a/embed.h
+++ b/embed.h
@@ -1691,6 +1691,8 @@
 #ifdef PERL_CORE
 #define my_clearenv		Perl_my_clearenv
 #endif
+#ifdef PERL_IMPLICIT_CONTEXT
+#endif
 #define ck_anoncode		Perl_ck_anoncode
 #define ck_bitop		Perl_ck_bitop
 #define ck_concat		Perl_ck_concat
@@ -3727,6 +3729,10 @@
 #ifdef PERL_CORE
 #define my_clearenv()		Perl_my_clearenv(aTHX)
 #endif
+#ifdef PERL_IMPLICIT_CONTEXT
+#ifdef PERL_CORE
+#endif
+#endif
 #define ck_anoncode(a)		Perl_ck_anoncode(aTHX_ a)
 #define ck_bitop(a)		Perl_ck_bitop(aTHX_ a)
 #define ck_concat(a)		Perl_ck_concat(aTHX_ a)
diff --git a/embedvar.h b/embedvar.h
index ca344b8..3f4a880 100644
--- a/embedvar.h
+++ b/embedvar.h
@@ -320,6 +320,8 @@
 #define PL_multi_open		(vTHX->Imulti_open)
 #define PL_multi_start		(vTHX->Imulti_start)
 #define PL_multiline		(vTHX->Imultiline)
+#define PL_my_cxt_list		(vTHX->Imy_cxt_list)
+#define PL_my_cxt_size		(vTHX->Imy_cxt_size)
 #define PL_nexttoke		(vTHX->Inexttoke)
 #define PL_nexttype		(vTHX->Inexttype)
 #define PL_nextval		(vTHX->Inextval)
@@ -600,6 +602,8 @@
 #define PL_Imulti_open		PL_multi_open
 #define PL_Imulti_start		PL_multi_start
 #define PL_Imultiline		PL_multiline
+#define PL_Imy_cxt_list		PL_my_cxt_list
+#define PL_Imy_cxt_size		PL_my_cxt_size
 #define PL_Inexttoke		PL_nexttoke
 #define PL_Inexttype		PL_nexttype
 #define PL_Inextval		PL_nextval
@@ -862,6 +866,10 @@
 #define PL_Gmalloc_mutex	(my_vars->Gmalloc_mutex)
 #define PL_mmap_page_size	(my_vars->Gmmap_page_size)
 #define PL_Gmmap_page_size	(my_vars->Gmmap_page_size)
+#define PL_my_ctx_mutex		(my_vars->Gmy_ctx_mutex)
+#define PL_Gmy_ctx_mutex	(my_vars->Gmy_ctx_mutex)
+#define PL_my_cxt_index		(my_vars->Gmy_cxt_index)
+#define PL_Gmy_cxt_index	(my_vars->Gmy_cxt_index)
 #define PL_op_mutex		(my_vars->Gop_mutex)
 #define PL_Gop_mutex		(my_vars->Gop_mutex)
 #define PL_op_seq		(my_vars->Gop_seq)
@@ -915,6 +923,8 @@
 #define PL_Ghexdigit		PL_hexdigit
 #define PL_Gmalloc_mutex	PL_malloc_mutex
 #define PL_Gmmap_page_size	PL_mmap_page_size
+#define PL_Gmy_ctx_mutex	PL_my_ctx_mutex
+#define PL_Gmy_cxt_index	PL_my_cxt_index
 #define PL_Gop_mutex		PL_op_mutex
 #define PL_Gop_seq		PL_op_seq
 #define PL_Gop_sequence		PL_op_sequence
diff --git a/ext/XS/APItest/APItest.xs b/ext/XS/APItest/APItest.xs
index 22279bc..c2a6478 100644
--- a/ext/XS/APItest/APItest.xs
+++ b/ext/XS/APItest/APItest.xs
@@ -16,16 +16,31 @@ typedef struct {
 START_MY_CXT
 
 /* indirect functions to test the [pa]MY_CXT macros */
+
 int
 my_cxt_getint_p(pMY_CXT)
 {
     return MY_CXT.i;
 }
+
 void
 my_cxt_setint_p(pMY_CXT_ int i)
 {
     MY_CXT.i = i;
 }
+
+SV*
+my_cxt_getsv_interp()
+{
+#ifdef PERL_IMPLICIT_CONTEXT
+    dTHX;
+    dMY_CXT_INTERP(my_perl);
+#else
+    dMY_CXT;
+#endif
+    return MY_CXT.sv;
+}
+
 void
 my_cxt_setsv_p(SV* sv _pMY_CXT)
 {
@@ -33,7 +48,6 @@ my_cxt_setsv_p(SV* sv _pMY_CXT)
 }
 
 
-
 /* from exception.c */
 int exception(int);
 
@@ -477,9 +491,8 @@ my_cxt_setint(i)
 void
 my_cxt_getsv()
     PPCODE:
-	dMY_CXT;
 	EXTEND(SP, 1);
-	ST(0) = MY_CXT.sv;
+	ST(0) = my_cxt_getsv_interp();
 	XSRETURN(1);
 
 void
diff --git a/intrpvar.h b/intrpvar.h
index 04ea137..931ac46 100644
--- a/intrpvar.h
+++ b/intrpvar.h
@@ -517,6 +517,12 @@ PERLVARI(Isuidscript, int, -1)	/* fd for suid script */
 /* File descriptor to talk to the child which dumps scalars.  */
 PERLVARI(Idumper_fd, int, -1)
 #endif
+
+#ifdef PERL_IMPLICIT_CONTEXT
+PERLVARI(Imy_cxt_size, int, -1)		/* size of PL_my_cxt_list */
+PERLVARI(Imy_cxt_list, void **, NULL) /* per-module array of MY_CXT pointers */
+#endif
+
 /* New variables must be added to the very end, before this comment,
  * for binary compatibility (the offsets of the old members must not change).
  * (Don't forget to add your variable also to perl_clone()!)
diff --git a/perl.h b/perl.h
index f478c22..d4efd90 100644
--- a/perl.h
+++ b/perl.h
@@ -5094,6 +5094,7 @@ typedef struct am_table_short AMTS;
  * Code that uses these macros is responsible for the following:
  * 1. #define MY_CXT_KEY to a unique string, e.g.
  *    "DynaLoader::_guts" XS_VERSION
+ *    XXX in the current implementation, this string is ignored.
  * 2. Declare a typedef named my_cxt_t that is a structure that contains
  *    all the data that needs to be interpreter-local.
  * 3. Use the START_MY_CXT macro after the declaration of my_cxt_t.
@@ -5110,35 +5111,30 @@ typedef struct am_table_short AMTS;
 /* This must appear in all extensions that define a my_cxt_t structure,
  * right after the definition (i.e. at file scope).  The non-threads
  * case below uses it to declare the data as static. */
-#define START_MY_CXT
-
-/* Fetches the SV that keeps the per-interpreter data. */
-#define dMY_CXT_SV \
-	SV *my_cxt_sv = *hv_fetch(PL_modglobal, MY_CXT_KEY,		\
-				  sizeof(MY_CXT_KEY)-1, TRUE)
+#define START_MY_CXT static int my_cxt_index = -1;
 
 /* This declaration should be used within all functions that use the
  * interpreter-local data. */
 #define dMY_CXT	\
-	dMY_CXT_SV;							\
-	my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*, SvUV(my_cxt_sv))
+	my_cxt_t *my_cxtp = (my_cxt_t *)PL_my_cxt_list[my_cxt_index]
+#define dMY_CXT_INTERP(my_perl)	\
+	my_cxt_t *my_cxtp = (my_cxt_t *)(my_perl)->Imy_cxt_list[my_cxt_index]
 
 /* Creates and zeroes the per-interpreter data.
  * (We allocate my_cxtp in a Perl SV so that it will be released when
  * the interpreter goes away.) */
 #define MY_CXT_INIT \
-	dMY_CXT_SV;							\
-	/* newSV() allocates one more than needed */			\
-	my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\
-	Zero(my_cxtp, 1, my_cxt_t);					\
-	sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+	my_cxt_t *my_cxtp = \
+	    (my_cxt_t*)Perl_my_cxt_init(aTHX_ &my_cxt_index, sizeof(my_cxt_t))
+#define MY_CXT_INIT_INTERP(my_perl) \
+	my_cxt_t *my_cxtp = \
+	    (my_cxt_t*)Perl_my_cxt_init(my_perl, &my_cxt_index, sizeof(my_cxt_t))
 
 /* Clones the per-interpreter data. */
 #define MY_CXT_CLONE \
-	dMY_CXT_SV;							\
 	my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\
-	Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t);\
-	sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+	Copy(PL_my_cxt_list[my_cxt_index], my_cxtp, 1, my_cxt_t);\
+	PL_my_cxt_list[my_cxt_index] = my_cxtp				\
 
 /* This macro must be used to access members of the my_cxt_t structure.
  * e.g. MYCXT.some_data */
@@ -5153,7 +5149,7 @@ typedef struct am_table_short AMTS;
 #define aMY_CXT_	aMY_CXT,
 #define _aMY_CXT	,aMY_CXT
 
-#else /* USE_ITHREADS */
+#else /* PERL_IMPLICIT_CONTEXT */
 
 #define START_MY_CXT	static my_cxt_t my_cxt;
 #define dMY_CXT_SV	dNOOP
@@ -5169,7 +5165,7 @@ typedef struct am_table_short AMTS;
 #define aMY_CXT_
 #define _aMY_CXT
 
-#endif /* !defined(USE_ITHREADS) */
+#endif /* !defined(PERL_IMPLICIT_CONTEXT) */
 
 #ifdef I_FCNTL
 #  include <fcntl.h>
diff --git a/perlapi.h b/perlapi.h
index fff51f6..8a8aa00 100644
--- a/perlapi.h
+++ b/perlapi.h
@@ -438,6 +438,10 @@ END_EXTERN_C
 #define PL_multi_start		(*Perl_Imulti_start_ptr(aTHX))
 #undef  PL_multiline
 #define PL_multiline		(*Perl_Imultiline_ptr(aTHX))
+#undef  PL_my_cxt_list
+#define PL_my_cxt_list		(*Perl_Imy_cxt_list_ptr(aTHX))
+#undef  PL_my_cxt_size
+#define PL_my_cxt_size		(*Perl_Imy_cxt_size_ptr(aTHX))
 #undef  PL_nexttoke
 #define PL_nexttoke		(*Perl_Inexttoke_ptr(aTHX))
 #undef  PL_nexttype
@@ -926,6 +930,10 @@ END_EXTERN_C
 #define PL_malloc_mutex		(*Perl_Gmalloc_mutex_ptr(NULL))
 #undef  PL_mmap_page_size
 #define PL_mmap_page_size	(*Perl_Gmmap_page_size_ptr(NULL))
+#undef  PL_my_ctx_mutex
+#define PL_my_ctx_mutex		(*Perl_Gmy_ctx_mutex_ptr(NULL))
+#undef  PL_my_cxt_index
+#define PL_my_cxt_index		(*Perl_Gmy_cxt_index_ptr(NULL))
 #undef  PL_op_mutex
 #define PL_op_mutex		(*Perl_Gop_mutex_ptr(NULL))
 #undef  PL_op_seq
diff --git a/perlvars.h b/perlvars.h
index 9f3a399..c15b666 100644
--- a/perlvars.h
+++ b/perlvars.h
@@ -124,4 +124,9 @@ PERLVARI(Gop_seq, UV, 0) /* dump.c */
 PERLVAR(Gtimesbase, struct tms)
 #endif
 
+/* allocate a unique index to every module that calls MY_CXT_INIT */
 
+#ifdef PERL_IMPLICIT_CONTEXT
+PERLVAR(Gmy_ctx_mutex, perl_mutex)
+PERLVARI(Gmy_cxt_index, int, 0)
+#endif
diff --git a/pod/perlxs.pod b/pod/perlxs.pod
index b3ba08f..e6f1862 100644
--- a/pod/perlxs.pod
+++ b/pod/perlxs.pod
@@ -1926,7 +1926,6 @@ Below is an example module that makes use of the macros.
 	CODE:
 	MY_CXT_CLONE;
 
-
 B<REFERENCE>
 
 =over 5
@@ -2013,8 +2012,19 @@ my_cxt_t structure. Calling C<MY_CXT_CLONE> (typically via the package's
 C<CLONE()> function), causes a byte-for-byte copy of the structure to be
 taken, and any future dMY_CXT will cause the copy to be accessed instead.
 
+=item MY_CXT_INIT_INTERP(my_perl)
+
+=item dMY_CXT_INTERP(my_perl)
+
+These are versions of the macros which take an explicit interpreter as an
+argument.
+
 =back
 
+Note that these macros will only work together within the I<same> source
+file; that is, a dMY_CTX in one source file will access a different structure
+than a dMY_CTX in another source file.
+
 =head1 EXAMPLES
 
 File C<RPC.xs>: Interface to some ONC+ RPC bind library functions.
diff --git a/proto.h b/proto.h
index e115a41..fbf3c86 100644
--- a/proto.h
+++ b/proto.h
@@ -4206,6 +4206,13 @@ PERL_CALLCONV int	Perl_my_sprintf(char *buffer, const char *pat, ...)
 
 PERL_CALLCONV void	Perl_my_clearenv(pTHX);
 
+#ifdef PERL_IMPLICIT_CONTEXT
+PERL_CALLCONV void*	Perl_my_cxt_init(pTHX_ int *index, size_t size)
+			__attribute__nonnull__(pTHX_1);
+
+#endif
+
+
 END_EXTERN_C
 /*
  * ex: set ts=8 sts=4 sw=4 noet:
diff --git a/sv.c b/sv.c
index d797a9f..f11f219 100644
--- a/sv.c
+++ b/sv.c
@@ -10394,6 +10394,14 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     }
     else
 	PL_exitlist	= (PerlExitListEntry*)NULL;
+
+    PL_my_cxt_size = proto_perl->Imy_cxt_size;
+    if (PL_my_cxt_size) {
+	Newx(PL_my_cxt_list, PL_my_cxt_size, void *);
+	Copy(proto_perl->Imy_cxt_list, PL_my_cxt_list, PL_my_cxt_size, void *);
+    }
+    else
+	PL_my_cxt_list	= (void**)NULL;
     PL_modglobal	= hv_dup_inc(proto_perl->Imodglobal, param);
     PL_custom_op_names  = hv_dup_inc(proto_perl->Icustom_op_names,param);
     PL_custom_op_descs  = hv_dup_inc(proto_perl->Icustom_op_descs,param);
diff --git a/util.c b/util.c
index d681d04..4976c75 100644
--- a/util.c
+++ b/util.c
@@ -5199,6 +5199,46 @@ Perl_my_clearenv(pTHX)
 #endif /* PERL_MICRO */
 }
 
+#ifdef PERL_IMPLICIT_CONTEXT
+
+/* implements the MY_CXT_INIT macro. The first time a module is loaded,
+the global PL_my_cxt_index is incremented, and that value is assigned to
+that module's static my_cxt_index (who's address is passed as an arg).
+Then, for each interpreter this function is called for, it makes sure a
+void* slot is available to hang the static data off, by allocating or
+extending the interpreter's PL_my_cxt_list array */
+
+void *
+Perl_my_cxt_init(pTHX_ int *index, size_t size)
+{
+    void *p;
+    if (*index == -1) {
+	/* this module hasn't been allocated an index yet */
+	MUTEX_LOCK(&PL_my_ctx_mutex);
+	*index = PL_my_cxt_index++;
+	MUTEX_UNLOCK(&PL_my_ctx_mutex);
+    }
+    
+    /* make sure the array is big enough */
+    if (PL_my_cxt_size < *index + 1) {
+	if (PL_my_cxt_list) {
+	    while (PL_my_cxt_size < *index + 1)
+		PL_my_cxt_size *= 2;
+	    Renew(PL_my_cxt_list, PL_my_cxt_size, void *);
+	}
+	else {
+	    PL_my_cxt_size = 16;
+	    Newx(PL_my_cxt_list, PL_my_cxt_size, void *);
+	}
+    }
+    /* newSV() allocates one more than needed */
+    p = (void*)SvPVX(newSV(size-1));
+    PL_my_cxt_list[*index] = p;
+    Zero(p, size, char);
+    return p;
+}
+#endif
+
 /*
  * Local variables:
  * c-indentation-style: bsd