Hello all,

The current Parrot interface to dlopen on UNIX systems is incomplete; it does
not allow passing control parameters, one of which is needed for the correct
operation of Blizkost (the Perl 5 to Parrot adaptor which I am working on for
Rakudo *).  I beleive the best place to add this functionality is in Parrot
itself, as this avoids any duplication of the configuration logic required to
bind to the dynamic linker portably.  This patch implements a portable and
extensible interface for Parrot extensions to pass data to the Parrot dynamic
linking mechanism.  Is this acceptable for Parrot?

This is my first Parrot patch and so I especially welcome all feedback,
especially as regarding the PIR-level interface.

Thank you.
-Stefan (sorear on #parrot)
Index: src/ops/core.ops
===================================================================
--- src/ops/core.ops	(revision 45050)
+++ src/ops/core.ops	(working copy)
@@ -1209,8 +1209,22 @@
 
 =item B<loadlib>(out PMC, in STR)
 
-Load a dynamic link library named $2 and store it in $1.
+=item B<loadlib>(out PMC, in STR, in PMC)
 
+Load a dynamic link library named $2 and store it in $1. $3, if
+provided, controls library loading and initialization; currently,
+we expect a bitmask accessible as an integer.  Bit definitions are
+accessible from PASM if F<dlopenflags.pasm> is included.  The current
+bits are:
+
+=over 4
+
+=item PARROT_DLOPEN_GLOBAL
+
+Make any symbols in the library accessible to other libraries loaded.
+
+=back
+
 =item B<dlfunc>(out PMC, invar PMC, in STR, in STR)
 
 Look up symbol $3 in library $2 with signature $4, and put the
@@ -1250,6 +1264,10 @@
     $1 = Parrot_load_lib(interp, $2, NULL);
 }
 
+inline op loadlib(out PMC, in STR, in PMC) {
+    $1 = Parrot_load_lib(interp, $2, $3);
+}
+
 op dlfunc(out PMC, invar PMC, in STR, in STR) {
     char * const  name      = Parrot_str_to_cstring(interp, ($3));
     void         *dl_handle = NULL;
Index: src/ops/ops.num
===================================================================
--- src/ops/ops.num	(revision 45050)
+++ src/ops/ops.num	(working copy)
@@ -1271,3 +1271,7 @@
 find_name_p_sc                 1247
 find_sub_not_null_p_s          1248
 find_sub_not_null_p_sc         1249
+loadlib_p_s_p                  1250
+loadlib_p_sc_p                 1251
+loadlib_p_s_pc                 1252
+loadlib_p_sc_pc                1253
Index: src/dynext.c
===================================================================
--- src/dynext.c	(revision 45050)
+++ src/dynext.c	(working copy)
@@ -42,20 +42,23 @@
 
 PARROT_WARN_UNUSED_RESULT
 PARROT_CAN_RETURN_NULL
-static void * dlopen_string(PARROT_INTERP, ARGIN(STRING *path))
+static void * dlopen_string(PARROT_INTERP,
+    Parrot_dlopen_flags flags,
+    ARGIN(STRING *path))
         __attribute__nonnull__(1)
-        __attribute__nonnull__(2);
+        __attribute__nonnull__(3);
 
 PARROT_WARN_UNUSED_RESULT
 PARROT_CAN_RETURN_NULL
 static STRING * get_path(PARROT_INTERP,
     ARGMOD_NULLOK(STRING *lib),
+    Parrot_dlopen_flags flags,
     ARGOUT(void **handle),
     ARGIN(STRING *wo_ext),
     ARGIN_NULLOK(STRING *ext))
         __attribute__nonnull__(1)
-        __attribute__nonnull__(3)
         __attribute__nonnull__(4)
+        __attribute__nonnull__(5)
         FUNC_MODIFIES(*lib)
         FUNC_MODIFIES(*handle);
 
@@ -218,9 +221,11 @@
 
 /*
 
-=item C<static void * dlopen_string(PARROT_INTERP, STRING *path)>
+=item C<static void * dlopen_string(PARROT_INTERP, Parrot_dlopen_flags flags,
+STRING *path)>
 
-Call Parrot_dlopen with the Parrot String argument converted to C string.
+Call Parrot_dlopen with the Parrot String argument converted to C string.  The
+flags argument will be converted into native form and used if applicable.
 
 =cut
 
@@ -229,20 +234,20 @@
 PARROT_WARN_UNUSED_RESULT
 PARROT_CAN_RETURN_NULL
 static void *
-dlopen_string(PARROT_INTERP, ARGIN(STRING *path))
+dlopen_string(PARROT_INTERP, Parrot_dlopen_flags flags, ARGIN(STRING *path))
 {
     ASSERT_ARGS(dlopen_string)
 
     char * const pathstr = Parrot_str_to_cstring(interp, path);
-    void *       handle  = Parrot_dlopen(pathstr);
+    void *       handle  = Parrot_dlopen(pathstr, flags);
     Parrot_str_free_cstring(pathstr);
     return handle;
 }
 
 /*
 
-=item C<static STRING * get_path(PARROT_INTERP, STRING *lib, void **handle,
-STRING *wo_ext, STRING *ext)>
+=item C<static STRING * get_path(PARROT_INTERP, STRING *lib, Parrot_dlopen_flags
+flags, void **handle, STRING *wo_ext, STRING *ext)>
 
 Return path and handle of a dynamic lib, setting lib_name to just the filestem
 (i.e. without path or extension) as a freshly-allocated C string.
@@ -254,8 +259,9 @@
 PARROT_WARN_UNUSED_RESULT
 PARROT_CAN_RETURN_NULL
 static STRING *
-get_path(PARROT_INTERP, ARGMOD_NULLOK(STRING *lib), ARGOUT(void **handle),
-        ARGIN(STRING *wo_ext), ARGIN_NULLOK(STRING *ext))
+get_path(PARROT_INTERP, ARGMOD_NULLOK(STRING *lib), Parrot_dlopen_flags flags,
+        ARGOUT(void **handle), ARGIN(STRING *wo_ext),
+        ARGIN_NULLOK(STRING *ext))
 {
     ASSERT_ARGS(get_path)
     STRING *path, *full_name;
@@ -268,7 +274,7 @@
                                                      PARROT_LIB_DYN_EXTS);
 
     if (lib == NULL) {
-        *handle = Parrot_dlopen((char *)NULL);
+        *handle = Parrot_dlopen((char *)NULL, flags);
         if (*handle) {
             return string_from_literal(interp, "");
         }
@@ -292,7 +298,7 @@
             path = Parrot_locate_runtime_file_str(interp, full_name,
                     PARROT_RUNTIME_FT_DYNEXT);
             if (path) {
-                *handle = dlopen_string(interp, path);
+                *handle = dlopen_string(interp, flags, path);
                 if (*handle) {
                     return path;
                 }
@@ -307,7 +313,7 @@
              * File with extension and prefix was not found,
              * so try file.extension w/o prefix
              */
-            *handle = dlopen_string(interp, full_name);
+            *handle = dlopen_string(interp, flags, full_name);
             if (*handle) {
                 return full_name;
             }
@@ -322,7 +328,7 @@
     full_name = Parrot_locate_runtime_file_str(interp, lib,
             PARROT_RUNTIME_FT_DYNEXT);
     if (full_name) {
-        *handle = dlopen_string(interp, full_name);
+        *handle = dlopen_string(interp, flags, full_name);
         if (*handle) {
             return full_name;
         }
@@ -333,7 +339,7 @@
      */
 #ifdef WIN32
     if (!STRING_IS_EMPTY(lib) && memcmp(lib->strstart, "lib", 3) == 0) {
-        *handle = Parrot_dlopen((char *)lib->strstart + 3);
+        *handle = Parrot_dlopen((char *)lib->strstart + 3, 0);
         if (*handle) {
             path = Parrot_str_substr(interp, lib, 3, lib->strlen - 3, NULL, 0);
             return path;
@@ -347,7 +353,7 @@
         path = Parrot_str_append(interp, CONST_STRING(interp, "cyg"),
             Parrot_str_substr(interp, lib, 3, lib->strlen - 3, NULL, 0));
 
-        *handle = dlopen_string(interp, path);
+        *handle = dlopen_string(interp, flags, path);
 
         if (*handle)
             return path;
@@ -356,7 +362,7 @@
 
     /* And after-finally,  let the OS use his own search */
     if (!STRING_IS_EMPTY(lib)) {
-        *handle = dlopen_string(interp, lib);
+        *handle = dlopen_string(interp, flags, lib);
         if (*handle)
             return lib;
     }
@@ -606,11 +612,13 @@
 
 /*
 
-=item C<PMC * Parrot_load_lib(PARROT_INTERP, STRING *lib, PMC *initializer)>
+=item C<PMC * Parrot_load_lib(PARROT_INTERP, STRING *lib, PMC *parameters)>
 
 Dynamic library loader.
 
-C<initializer> is currently unused.
+C<parameters>, if not null, points to something which controls library
+loading and initialization.  Currently just its integer value is used,
+interpreted as C<PDLOpen_flags>.
 
 Calls C<Parrot_lib_%s_load()> which performs the registration of the lib
 once C<Parrot_lib_%s_init()> gets called (if exists) to perform thread
@@ -633,7 +641,7 @@
 PARROT_WARN_UNUSED_RESULT
 PARROT_CANNOT_RETURN_NULL
 PMC *
-Parrot_load_lib(PARROT_INTERP, ARGIN_NULLOK(STRING *lib), SHIM(PMC *initializer))
+Parrot_load_lib(PARROT_INTERP, ARGIN_NULLOK(STRING *lib), PMC *parameters)
 {
     ASSERT_ARGS(Parrot_load_lib)
     void   *handle;
@@ -641,6 +649,7 @@
     STRING *path;
     STRING *lib_name, *wo_ext, *ext;    /* library stem without path
                                          * or extension.  */
+    Parrot_dlopen_flags flags;
     /* Find the pure library name, without path or extension.  */
     /*
      * TODO move the class_count_mutex here
@@ -662,7 +671,12 @@
         return lib_pmc;
     }
 
-    path = get_path(interp, lib, &handle, wo_ext, ext);
+    flags = 0;
+    if (!PMC_IS_NULL(parameters)) {
+        flags = VTABLE_get_integer(interp, parameters);
+    }
+
+    path = get_path(interp, lib, flags, &handle, wo_ext, ext);
     if (!path || !handle) {
         /*
          * XXX Parrot_ex_throw_from_c_args? return PMCNULL?
Index: include/parrot/dynext.h
===================================================================
--- include/parrot/dynext.h	(revision 45050)
+++ include/parrot/dynext.h	(working copy)
@@ -41,7 +41,7 @@
 PARROT_CANNOT_RETURN_NULL
 PMC * Parrot_load_lib(PARROT_INTERP,
     ARGIN_NULLOK(STRING *lib),
-    SHIM(PMC *initializer))
+    PMC *initializer)
         __attribute__nonnull__(1);
 
 #define ASSERT_ARGS_Parrot_clone_lib_into __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
Index: MANIFEST.generated
===================================================================
--- MANIFEST.generated	(revision 45050)
+++ MANIFEST.generated	(working copy)
@@ -118,6 +118,7 @@
 runtime/parrot/include/cclass.pasm                [main]
 runtime/parrot/include/config.fpmc                []
 runtime/parrot/include/datatypes.pasm             [main]
+runtime/parrot/include/dlopenflags.pasm           [main]
 runtime/parrot/include/errors.pasm                [main]
 runtime/parrot/include/except_severity.pasm       [main]
 runtime/parrot/include/except_types.pasm          [main]
Index: config/gen/makefiles/root.in
===================================================================
--- config/gen/makefiles/root.in	(revision 45050)
+++ config/gen/makefiles/root.in	(working copy)
@@ -209,6 +209,7 @@
 	runtime/parrot/include/stdio.pasm \
 	runtime/parrot/include/socket.pasm \
 	runtime/parrot/include/libpaths.pasm \
+	runtime/parrot/include/dlopenflags.pasm \
 	runtime/parrot/include/longopt.pasm \
 	runtime/parrot/include/packfile_segments.pasm \
 	runtime/parrot/include/packfile_constants.pasm \
@@ -1088,6 +1089,9 @@
 runtime/parrot/include/libpaths.pasm : $(INC_DIR)/library.h $(H2INC)
 	$(PERL) $(H2INC) $(INC_DIR)/library.h $@
 
+runtime/parrot/include/dlopenflags.pasm : $(INC_DIR)/platform_interface.h $(H2INC)
+	$(PERL) $(H2INC) $(INC_DIR)/platform_interface.h $@
+
 runtime/parrot/include/datatypes.pasm : $(INC_DIR)/datatypes.h $(H2INC)
 	$(PERL) $(H2INC) $(INC_DIR)/datatypes.h $@
 
Index: config/gen/platform/win32/dl.c
===================================================================
--- config/gen/platform/win32/dl.c	(revision 45050)
+++ config/gen/platform/win32/dl.c	(working copy)
@@ -23,7 +23,8 @@
 
 /*
 
-=item C<void * Parrot_dlopen(const char *filename)>
+=item C<void * Parrot_dlopen(const char *filename, SHIM(Parrot_dlopen_flags
+flags))>
 
 Opens a dynamic library, and returns a system handle to that library.
 Returns Parrot_dlerror() on failure.
@@ -33,7 +34,7 @@
 */
 
 void *
-Parrot_dlopen(const char *filename)
+Parrot_dlopen(const char *filename, SHIM(Parrot_dlopen_flags flags))
 {
     return LoadLibrary(filename);
 }
Index: config/gen/platform/ansi/dl.c
===================================================================
--- config/gen/platform/ansi/dl.c	(revision 45050)
+++ config/gen/platform/ansi/dl.c	(working copy)
@@ -23,14 +23,15 @@
 
 /*
 
-=item C<void * Parrot_dlopen(const char *filename)>
+=item C<void * Parrot_dlopen(const char *filename, SHIM(Parrot_dlopen_flags
+flags)>
 
 =cut
 
 */
 
 void *
-Parrot_dlopen(const char *filename)
+Parrot_dlopen(const char *filename, SHIM(Parrot_dlopen_flags flags))
 {
     Parrot_warn(NULL, PARROT_WARNINGS_PLATFORM_FLAG, "Parrot_dlopen not implemented");
     return NULL;
Index: config/gen/platform/platform_interface.h
===================================================================
--- config/gen/platform/platform_interface.h	(revision 45050)
+++ config/gen/platform/platform_interface.h	(working copy)
@@ -73,7 +73,25 @@
 ** Dynamic Loading:
 */
 
-void *Parrot_dlopen(const char *filename);
+/*
+ * We need to at least provide access to global loading, because two kinds
+ * of extension need it.  First, if you are providing a C-level API to your
+ * extension, it needs to be possible for other extensions to resolve your
+ * symbols.  Second, if your extension loads a library which itself has
+ * extensions, and those extensions are not linked against the main library
+ * but use symbols from it, this flag is needed to prevent dynamic linker
+ * errors - notably, this is the case with Perl 5.
+ *
+ * All flags will be ignored on platforms for which they are inapplicable.
+ */
+
+/* &gen_from_enum(dlopenflags.pasm) */
+typedef enum Parrot_dlopen_enum {
+    Parrot_dlopen_global_FLAG   = 0x01,
+} Parrot_dlopen_flags;
+/* &end_gen */
+
+void *Parrot_dlopen(const char *filename, Parrot_dlopen_flags flags);
 const char *Parrot_dlerror(void);
 void *Parrot_dlsym(void *handle, const char *symbol);
 int Parrot_dlclose(void *handle);
Index: config/gen/platform/generic/dl.c
===================================================================
--- config/gen/platform/generic/dl.c	(revision 45050)
+++ config/gen/platform/generic/dl.c	(working copy)
@@ -29,17 +29,18 @@
 
 /*
 
-=item C<void * Parrot_dlopen(const char *filename)>
+=item C<void * Parrot_dlopen(const char *filename, Parrot_dlopen_flags flags)>
 
 =cut
 
 */
 
 void *
-Parrot_dlopen(const char *filename)
+Parrot_dlopen(const char *filename, Parrot_dlopen_flags flags)
 {
 #ifdef PARROT_HAS_HEADER_DLFCN
-    return dlopen(filename, PARROT_DLOPEN_FLAGS);
+    return dlopen(filename, PARROT_DLOPEN_FLAGS
+                    | ((flags & Parrot_dlopen_global_FLAG) ? RTLD_GLOBAL : 0));
 #else
     return 0;
 #endif

Attachment: signature.asc
Description: Digital signature

_______________________________________________
http://lists.parrot.org/mailman/listinfo/parrot-dev

Reply via email to