Commit | Line | Data |
---|---|---|
ac9901e0 PP |
1 | /* dl_dllload.xs |
2 | * | |
3 | * Platform: OS/390, possibly others that use dllload(),dllfree() (VM/ESA?). | |
4 | * Authors: John Goodyear && Peter Prymmer | |
5 | * Created: 28 October 2000 | |
6 | * Modified: | |
7 | * 16 January 2001 - based loosely on dl_dlopen.xs. | |
8 | */ | |
9 | ||
10 | /* Porting notes: | |
11 | ||
12 | OS/390 Dynamic Loading functions: | |
13 | ||
14 | dllload | |
15 | ------- | |
16 | dllhandle * dllload(const char *dllName) | |
17 | ||
18 | This function takes the name of a dynamic object file and returns | |
19 | a descriptor which can be used by dlllqueryfn() and/or dllqueryvar() | |
20 | later. If dllName contains a slash, it is used to locate the dll. | |
21 | If not then the LIBPATH environment variable is used to | |
22 | search for the requested dll (at least within the HFS). | |
23 | It returns NULL on error and sets errno. | |
24 | ||
25 | dllfree | |
26 | ------- | |
27 | int dllfree(dllhandle *handle); | |
28 | ||
29 | dllfree() decrements the load count for the dll and frees | |
30 | it if the count is 0. It returns zero on success, and | |
31 | non-zero on failure. | |
32 | ||
33 | dllqueryfn && dllqueryvar | |
34 | ------------------------- | |
35 | void (* dllqueryfn(dllhandle *handle, const char *function))(); | |
36 | void * dllqueryvar(dllhandle *handle, const char *symbol); | |
37 | ||
38 | dllqueryfn() takes the handle returned from dllload() and the name | |
39 | of a function to get the address of. If the function was found | |
40 | a pointer is returned, otherwise NULL is returned. | |
41 | ||
42 | dllqueryvar() takes the handle returned from dllload() and the name | |
43 | of a symbol to get the address of. If the variable was found a | |
44 | pointer is returned, otherwise NULL is returned. | |
45 | ||
46 | The XS dl_find_symbol() first calls dllqueryfn(). If it fails | |
47 | dlqueryvar() is then called. | |
48 | ||
49 | strerror | |
50 | -------- | |
51 | char * strerror(int errno) | |
52 | ||
53 | Returns a null-terminated string which describes the last error | |
54 | that occurred with other functions (not necessarily unique to | |
55 | dll loading). | |
56 | ||
57 | Return Types | |
58 | ============ | |
59 | In this implementation the two functions, dl_load_file() && | |
60 | dl_find_symbol(), return (void *). This is primarily because the | |
61 | dlopen() && dlsym() style dynamic linker calls return (void *). | |
62 | We suspect that casting to (void *) may be easier than teaching XS | |
63 | typemaps about the (dllhandle *) type. | |
64 | ||
65 | Dealing with Error Messages | |
66 | =========================== | |
67 | In order to make the handling of dynamic linking errors as generic as | |
68 | possible you should store any error messages associated with your | |
69 | implementation with the StoreError function. | |
70 | ||
71 | In the case of OS/390 the function strerror(errno) returns the error | |
72 | message associated with the last dynamic link error. As the S/390 | |
73 | dynamic linker functions dllload() && dllqueryvar() both return NULL | |
74 | on error every call to an S/390 dynamic link routine is coded | |
75 | like this: | |
76 | ||
77 | RETVAL = dllload(filename) ; | |
78 | if (RETVAL == NULL) | |
79 | SaveError("%s",strerror(errno)) ; | |
80 | ||
81 | Note that SaveError() takes a printf format string. Use a "%s" as | |
82 | the first parameter if the error may contain any % characters. | |
83 | ||
84 | Other comments within the dl_dlopen.xs file may be helpful as well. | |
85 | */ | |
86 | ||
87 | #include "EXTERN.h" | |
88 | #include "perl.h" | |
89 | #include "XSUB.h" | |
90 | ||
91 | #include <dll.h> /* the dynamic linker include file for S/390 */ | |
92 | #include <errno.h> /* strerror() and friends */ | |
93 | ||
94 | #include "dlutils.c" /* SaveError() etc */ | |
95 | ||
96 | static void | |
97 | dl_private_init(pTHX) | |
98 | { | |
99 | (void)dl_generic_private_init(aTHX); | |
100 | } | |
101 | ||
102 | MODULE = DynaLoader PACKAGE = DynaLoader | |
103 | ||
104 | BOOT: | |
105 | (void)dl_private_init(aTHX); | |
106 | ||
107 | ||
108 | void * | |
109 | dl_load_file(filename, flags=0) | |
110 | char * filename | |
111 | int flags | |
112 | PREINIT: | |
113 | int mode = 0; | |
114 | CODE: | |
115 | { | |
116 | DLDEBUG(1,PerlIO_printf(Perl_debug_log, "dl_load_file(%s,%x):\n", filename,flags)); | |
117 | /* add a (void *) dllload(filename) ; cast if needed */ | |
118 | RETVAL = dllload(filename) ; | |
119 | DLDEBUG(2,PerlIO_printf(Perl_debug_log, " libref=%lx\n", (unsigned long) RETVAL)); | |
120 | ST(0) = sv_newmortal() ; | |
121 | if (RETVAL == NULL) | |
122 | SaveError(aTHX_ "%s",strerror(errno)) ; | |
123 | else | |
124 | sv_setiv( ST(0), PTR2IV(RETVAL)); | |
125 | } | |
126 | ||
127 | ||
128 | int | |
129 | dl_unload_file(libref) | |
130 | void * libref | |
131 | CODE: | |
132 | DLDEBUG(1,PerlIO_printf(Perl_debug_log, "dl_unload_file(%lx):\n", PTR2ul(libref))); | |
133 | /* RETVAL = (dllfree((dllhandle *)libref) == 0 ? 1 : 0); */ | |
134 | RETVAL = (dllfree(libref) == 0 ? 1 : 0); | |
135 | if (!RETVAL) | |
136 | SaveError(aTHX_ "%s", strerror(errno)) ; | |
137 | DLDEBUG(2,PerlIO_printf(Perl_debug_log, " retval = %d\n", RETVAL)); | |
138 | OUTPUT: | |
139 | RETVAL | |
140 | ||
141 | ||
142 | void * | |
143 | dl_find_symbol(libhandle, symbolname) | |
144 | void * libhandle | |
145 | char * symbolname | |
146 | CODE: | |
147 | DLDEBUG(2, PerlIO_printf(Perl_debug_log, | |
148 | "dl_find_symbol(handle=%lx, symbol=%s)\n", | |
149 | (unsigned long) libhandle, symbolname)); | |
150 | if((RETVAL = (void*)dllqueryfn(libhandle, symbolname)) == NULL) | |
151 | RETVAL = dllqueryvar(libhandle, symbolname); | |
152 | DLDEBUG(2, PerlIO_printf(Perl_debug_log, | |
153 | " symbolref = %lx\n", (unsigned long) RETVAL)); | |
154 | ST(0) = sv_newmortal() ; | |
155 | if (RETVAL == NULL) | |
156 | SaveError(aTHX_ "%s",strerror(errno)) ; | |
157 | else | |
158 | sv_setiv( ST(0), PTR2IV(RETVAL)); | |
159 | ||
160 | ||
161 | void | |
162 | dl_undef_symbols() | |
163 | PPCODE: | |
164 | ||
165 | ||
166 | ||
167 | # These functions should not need changing on any platform: | |
168 | ||
169 | void | |
170 | dl_install_xsub(perl_name, symref, filename="$Package") | |
171 | char * perl_name | |
172 | void * symref | |
d3f5e399 | 173 | const char * filename |
ac9901e0 PP |
174 | CODE: |
175 | DLDEBUG(2,PerlIO_printf(Perl_debug_log, "dl_install_xsub(name=%s, symref=%lx)\n", | |
176 | perl_name, (unsigned long) symref)); | |
77004dee NC |
177 | ST(0) = sv_2mortal(newRV((SV*)newXS_flags(perl_name, |
178 | (void(*)(pTHX_ CV *))symref, | |
179 | filename, NULL, | |
180 | XS_DYNAMIC_FILENAME))); | |
ac9901e0 PP |
181 | |
182 | ||
183 | char * | |
184 | dl_error() | |
185 | CODE: | |
cdc73a10 JH |
186 | dMY_CXT; |
187 | RETVAL = dl_last_error ; | |
ac9901e0 PP |
188 | OUTPUT: |
189 | RETVAL | |
190 | ||
8c472fc1 CB |
191 | #if defined(USE_ITHREADS) |
192 | ||
193 | void | |
194 | CLONE(...) | |
195 | CODE: | |
196 | MY_CXT_CLONE; | |
197 | ||
198 | /* MY_CXT_CLONE just does a memcpy on the whole structure, so to avoid | |
199 | * using Perl variables that belong to another thread, we create our | |
200 | * own for this thread. | |
201 | */ | |
202 | MY_CXT.x_dl_last_error = newSVpvn("", 0); | |
203 | ||
204 | #endif | |
205 | ||
ac9901e0 | 206 | # end. |