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 | ||
63d7ac5f | 108 | void |
ac9901e0 PP |
109 | dl_load_file(filename, flags=0) |
110 | char * filename | |
111 | int flags | |
112 | PREINIT: | |
113 | int mode = 0; | |
63d7ac5f S |
114 | void *retv; |
115 | PPCODE: | |
ac9901e0 PP |
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 */ | |
63d7ac5f S |
118 | retv = dllload(filename) ; |
119 | DLDEBUG(2,PerlIO_printf(Perl_debug_log, " libref=%lx\n", (unsigned long) retv)); | |
ac9901e0 | 120 | ST(0) = sv_newmortal() ; |
63d7ac5f | 121 | if (retv == NULL) |
ac9901e0 PP |
122 | SaveError(aTHX_ "%s",strerror(errno)) ; |
123 | else | |
63d7ac5f S |
124 | sv_setiv( ST(0), PTR2IV(retv)); |
125 | XSRETURN(1); | |
ac9901e0 PP |
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 | ||
63d7ac5f | 142 | void |
ac9901e0 PP |
143 | dl_find_symbol(libhandle, symbolname) |
144 | void * libhandle | |
145 | char * symbolname | |
63d7ac5f S |
146 | PREINIT: |
147 | void *retv; | |
148 | PPCODE: | |
ac9901e0 PP |
149 | DLDEBUG(2, PerlIO_printf(Perl_debug_log, |
150 | "dl_find_symbol(handle=%lx, symbol=%s)\n", | |
151 | (unsigned long) libhandle, symbolname)); | |
63d7ac5f S |
152 | if((retv = (void*)dllqueryfn(libhandle, symbolname)) == NULL) |
153 | retv = dllqueryvar(libhandle, symbolname); | |
ac9901e0 | 154 | DLDEBUG(2, PerlIO_printf(Perl_debug_log, |
63d7ac5f | 155 | " symbolref = %lx\n", (unsigned long) retv)); |
ac9901e0 | 156 | ST(0) = sv_newmortal() ; |
63d7ac5f | 157 | if (retv == NULL) |
ac9901e0 PP |
158 | SaveError(aTHX_ "%s",strerror(errno)) ; |
159 | else | |
63d7ac5f S |
160 | sv_setiv( ST(0), PTR2IV(retv)); |
161 | XSRETURN(1); | |
ac9901e0 PP |
162 | |
163 | ||
164 | void | |
165 | dl_undef_symbols() | |
63d7ac5f | 166 | CODE: |
ac9901e0 PP |
167 | |
168 | ||
169 | ||
170 | # These functions should not need changing on any platform: | |
171 | ||
172 | void | |
173 | dl_install_xsub(perl_name, symref, filename="$Package") | |
174 | char * perl_name | |
175 | void * symref | |
d3f5e399 | 176 | const char * filename |
63d7ac5f | 177 | PPCODE: |
ac9901e0 PP |
178 | DLDEBUG(2,PerlIO_printf(Perl_debug_log, "dl_install_xsub(name=%s, symref=%lx)\n", |
179 | perl_name, (unsigned long) symref)); | |
77004dee NC |
180 | ST(0) = sv_2mortal(newRV((SV*)newXS_flags(perl_name, |
181 | (void(*)(pTHX_ CV *))symref, | |
182 | filename, NULL, | |
183 | XS_DYNAMIC_FILENAME))); | |
63d7ac5f | 184 | XSRETURN(1); |
ac9901e0 PP |
185 | |
186 | ||
bb6a367a | 187 | SV * |
ac9901e0 PP |
188 | dl_error() |
189 | CODE: | |
cdc73a10 | 190 | dMY_CXT; |
bb6a367a | 191 | RETVAL = newSVsv(MY_CXT.x_dl_last_error); |
ac9901e0 PP |
192 | OUTPUT: |
193 | RETVAL | |
194 | ||
8c472fc1 CB |
195 | #if defined(USE_ITHREADS) |
196 | ||
197 | void | |
198 | CLONE(...) | |
199 | CODE: | |
200 | MY_CXT_CLONE; | |
201 | ||
3bd46979 DM |
202 | PERL_UNUSED_VAR(items); |
203 | ||
8c472fc1 CB |
204 | /* MY_CXT_CLONE just does a memcpy on the whole structure, so to avoid |
205 | * using Perl variables that belong to another thread, we create our | |
206 | * own for this thread. | |
207 | */ | |
c2b90b61 | 208 | MY_CXT.x_dl_last_error = newSVpvs(""); |
8c472fc1 CB |
209 | |
210 | #endif | |
211 | ||
ac9901e0 | 212 | # end. |