Use MAP_ANON instead of MAP_ANONYMOUS.
[kopensolaris-gnu/glibc.git] / elf / dl-close.c
1 /* Close a shared object opened by `_dl_open'.
2    Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <assert.h>
21 #include <dlfcn.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <bits/libc-lock.h>
25 #include <elf/ldsodefs.h>
26 #include <sys/types.h>
27 #include <sys/mman.h>
28
29
30 /* During the program run we must not modify the global data of
31    loaded shared object simultanously in two threads.  Therefore we
32    protect `dlopen' and `dlclose' in dlclose.c.  */
33 __libc_lock_define (extern, _dl_load_lock)
34
35 #define LOSE(s) _dl_signal_error (0, map->l_name, s)
36
37 void
38 internal_function
39 _dl_close (struct link_map *map)
40 {
41   struct link_map **list;
42   unsigned nsearchlist;
43   unsigned int i;
44
45   if (map->l_opencount == 0)
46     LOSE ("shared object not open");
47
48   /* Acquire the lock.  */
49   __libc_lock_lock (_dl_load_lock);
50
51   /* Decrement the reference count.  */
52   if (map->l_opencount > 1 || map->l_type != lt_loaded)
53     {
54       /* There are still references to this object.  Do nothing more.  */
55       --map->l_opencount;
56       __libc_lock_unlock (_dl_load_lock);
57       return;
58     }
59
60   list = map->l_searchlist.r_list;
61   nsearchlist = map->l_searchlist.r_nlist;
62
63   /* Call all termination functions at once.  */
64   for (i = 0; i < nsearchlist; ++i)
65     {
66       struct link_map *imap = list[i];
67       if (imap->l_opencount == 1 && imap->l_type == lt_loaded
68           && imap->l_info[DT_FINI]
69           /* Skip any half-cooked objects that were never initialized.  */
70           && imap->l_init_called)
71         {
72           /* When debugging print a message first.  */
73           if (_dl_debug_impcalls)
74             _dl_debug_message (1, "\ncalling fini: ", imap->l_name,
75                                "\n\n", NULL);
76           /* Call its termination function.  */
77           (*(void (*) (void)) ((void *) imap->l_addr
78                                + imap->l_info[DT_FINI]->d_un.d_ptr)) ();
79         }
80     }
81
82   /* Notify the debugger we are about to remove some loaded objects.  */
83   _r_debug.r_state = RT_DELETE;
84   _dl_debug_state ();
85
86   /* The search list contains a counted reference to each object it
87      points to, the 0th elt being MAP itself.  Decrement the reference
88      counts on all the objects MAP depends on.  */
89   for (i = 0; i < nsearchlist; ++i)
90     --list[i]->l_opencount;
91
92   /* Check each element of the search list to see if all references to
93      it are gone.  */
94   for (i = 0; i < nsearchlist; ++i)
95     {
96       struct link_map *imap = list[i];
97       if (imap->l_opencount == 0 && imap->l_type == lt_loaded)
98         {
99           struct libname_list *lnp;
100
101           /* That was the last reference, and this was a dlopen-loaded
102              object.  We can unmap it.  */
103           if (imap->l_global)
104             {
105               /* This object is in the global scope list.  Remove it.  */
106               unsigned int cnt = _dl_main_searchlist->r_nlist;
107
108               do
109                 --cnt;
110               while (_dl_main_searchlist->r_list[cnt] != imap);
111               while (cnt < _dl_main_searchlist->r_nlist)
112                 {
113                   _dl_main_searchlist->r_list[0]
114                     = _dl_main_searchlist->r_list[1];
115                   ++cnt;
116                 }
117               --_dl_main_searchlist->r_nlist;
118               if (_dl_main_searchlist->r_nlist
119                   == _dl_initial_searchlist.r_nlist)
120                 {
121                   /* All object dynamically loaded by the program are
122                      unloaded.  Free the memory allocated for the global
123                      scope variable.  */
124                   struct link_map **old = _dl_main_searchlist->r_list;
125
126                   /* Put the old map in.  */
127                   _dl_main_searchlist->r_list = _dl_initial_searchlist.r_list;
128                   /* Signal that the old map is used.  */
129                   _dl_global_scope_alloc = 0;
130
131                   /* Now free the old map.  */
132                   free (old);
133                 }
134             }
135
136           /* We can unmap all the maps at once.  We determined the
137              start address and length when we loaded the object and
138              the `munmap' call does the rest.  */
139           __munmap ((void *) imap->l_map_start,
140                     imap->l_map_end - imap->l_map_start);
141
142           /* Finally, unlink the data structure and free it.  */
143 #ifdef PIC
144           /* We will unlink the first object only if this is a statically
145              linked program.  */
146           assert (imap->l_prev != NULL);
147           imap->l_prev->l_next = imap->l_next;
148 #else
149           if (imap->l_prev != NULL)
150             imap->l_prev->l_next = imap->l_next;
151           else
152             _dl_loaded = imap->l_next;
153 #endif
154           if (imap->l_next)
155             imap->l_next->l_prev = imap->l_prev;
156
157           if (imap->l_versions != NULL)
158             free (imap->l_versions);
159           if (imap->l_origin != NULL && imap->l_origin != (char *) -1)
160             free ((char *) imap->l_origin);
161
162           /* This name always is allocated.  */
163           free (imap->l_name);
164           /* Remove the list with all the names of the shared object.  */
165           lnp = imap->l_libname;
166           do
167             {
168               struct libname_list *this = lnp;
169               lnp = lnp->next;
170               free (this);
171             }
172           while (lnp != NULL);
173
174           /* Remove the searchlists.  */
175           if (imap->l_searchlist.r_duplist != imap->l_searchlist.r_list)
176             {
177               /* If a r_list exists there always also is a r_duplist.  */
178               assert (imap->l_searchlist.r_list != NULL);
179               free (imap->l_searchlist.r_duplist);
180             }
181           if (imap != map && imap->l_searchlist.r_list != NULL)
182             free (imap->l_searchlist.r_list);
183
184           free (imap);
185         }
186     }
187
188   free (list);
189
190   /* Notify the debugger those objects are finalized and gone.  */
191   _r_debug.r_state = RT_CONSISTENT;
192   _dl_debug_state ();
193
194   /* Release the lock.  */
195   __libc_lock_unlock (_dl_load_lock);
196 }