1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22: #include <assert.h>
23: #include <dlfcn.h>
24: #include <inttypes.h>
25: #include <search.h>
26: #include <stdlib.h>
27: #include <string.h>
28: #include <bits/libc-lock.h>
29: #include <sys/param.h>
30:
31: #include <gconv_int.h>
32: #include <sysdep.h>
33:
34:
35: #ifdef DEBUG
36:
37: static void print_all (void);
38: #endif
39:
40:
41:
42:
43:
44:
45:
46:
47:
48: #define TRIES_BEFORE_UNLOAD 2
49:
50:
51:
52: static void *loaded;
53:
54:
55: static int
56: known_compare (const void *p1, const void *p2)
57: {
58: const struct __gconv_loaded_object *s1 =
59: (const struct __gconv_loaded_object *) p1;
60: const struct __gconv_loaded_object *s2 =
61: (const struct __gconv_loaded_object *) p2;
62:
63: return strcmp (s1->name, s2->name);
64: }
65:
66:
67:
68: struct __gconv_loaded_object *
69: internal_function
70: __gconv_find_shlib (const char *name)
71: {
72: struct __gconv_loaded_object *found;
73: void *keyp;
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84: keyp = __tfind (&name, &loaded, known_compare);
85: if (keyp == NULL)
86: {
87:
88: size_t namelen = strlen (name) + 1;
89:
90: found = malloc (sizeof (struct __gconv_loaded_object) + namelen);
91: if (found != NULL)
92: {
93:
94: found->name = (char *) memcpy (found + 1, name, namelen);
95: found->counter = -TRIES_BEFORE_UNLOAD - 1;
96: found->handle = NULL;
97:
98: if (__builtin_expect (__tsearch (found, &loaded, known_compare)
99: == NULL, 0))
100: {
101:
102: free (found);
103: found = NULL;
104: }
105: }
106: }
107: else
108: found = *(struct __gconv_loaded_object **) keyp;
109:
110:
111:
112:
113: if (found != NULL)
114: {
115: if (found->counter < -TRIES_BEFORE_UNLOAD)
116: {
117: assert (found->handle == NULL);
118: found->handle = __libc_dlopen (found->name);
119: if (found->handle != NULL)
120: {
121: found->fct = __libc_dlsym (found->handle, "gconv");
122: if (found->fct == NULL)
123: {
124:
125:
126: __gconv_release_shlib (found);
127: found = NULL;
128: }
129: else
130: {
131: found->init_fct = __libc_dlsym (found->handle, "gconv_init");
132: found->end_fct = __libc_dlsym (found->handle, "gconv_end");
133:
134: #ifdef PTR_MANGLE
135: PTR_MANGLE (found->fct);
136: if (found->init_fct != NULL)
137: PTR_MANGLE (found->init_fct);
138: if (found->end_fct != NULL)
139: PTR_MANGLE (found->end_fct);
140: #endif
141:
142:
143: found->counter = 1;
144: }
145: }
146: else
147:
148: found = NULL;
149: }
150: else if (found->handle != NULL)
151: found->counter = MAX (found->counter + 1, 1);
152: }
153:
154: return found;
155: }
156:
157:
158:
159:
160:
161: static struct __gconv_loaded_object *release_handle;
162:
163: static void
164: do_release_shlib (void *nodep, VISIT value, int level)
165: {
166: struct __gconv_loaded_object *obj = *(struct __gconv_loaded_object **) nodep;
167:
168: if (value != preorder && value != leaf)
169: return;
170:
171: if (obj == release_handle)
172: {
173:
174:
175: assert (obj->counter > 0);
176: --obj->counter;
177: }
178: else if (obj->counter <= 0 && obj->counter >= -TRIES_BEFORE_UNLOAD
179: && --obj->counter < -TRIES_BEFORE_UNLOAD && obj->handle != NULL)
180: {
181:
182: __libc_dlclose (obj->handle);
183: obj->handle = NULL;
184: }
185: }
186:
187:
188:
189: void
190: internal_function
191: __gconv_release_shlib (struct __gconv_loaded_object *handle)
192: {
193:
194: release_handle = handle;
195:
196:
197:
198:
199: __twalk (loaded, (__action_fn_t) do_release_shlib);
200: }
201:
202:
203:
204: static void __libc_freeres_fn_section
205: do_release_all (void *nodep)
206: {
207: struct __gconv_loaded_object *obj = (struct __gconv_loaded_object *) nodep;
208:
209:
210: if (obj->handle != NULL)
211: __libc_dlclose (obj->handle);
212:
213: free (obj);
214: }
215:
216: libc_freeres_fn (free_mem)
217: {
218: __tdestroy (loaded, do_release_all);
219: loaded = NULL;
220: }
221:
222:
223: #ifdef DEBUG
224: static void
225: do_print (const void *nodep, VISIT value, int level)
226: {
227: struct __gconv_loaded_object *obj = *(struct __gconv_loaded_object **) nodep;
228:
229: printf ("%10s: \"%s\", %d\n",
230: value == leaf ? "leaf" :
231: value == preorder ? "preorder" :
232: value == postorder ? "postorder" : "endorder",
233: obj->name, obj->counter);
234: }
235:
236: static void
237: print_all (void)
238: {
239: __twalk (loaded, do_print);
240: }
241: #endif