dynamic-ld.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1993-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <iostream>
00028 #include <list>
00029 
00030 #include "file-stat.h"
00031 #include "oct-env.h"
00032 #include "oct-time.h"
00033 #include "singleton-cleanup.h"
00034 
00035 #include <defaults.h>
00036 
00037 #include "defun.h"
00038 #include "dynamic-ld.h"
00039 #include "ov-fcn.h"
00040 #include "ov-dld-fcn.h"
00041 #include "ov-mex-fcn.h"
00042 #include "parse.h"
00043 #include "unwind-prot.h"
00044 #include "utils.h"
00045 #include "variables.h"
00046 
00047 #define STRINGIFY(s) STRINGIFY1(s)
00048 #define STRINGIFY1(s) #s
00049 
00050 class
00051 octave_shlib_list
00052 {
00053 public:
00054 
00055   typedef std::list<octave_shlib>::iterator iterator;
00056   typedef std::list<octave_shlib>::const_iterator const_iterator;
00057 
00058   static void append (const octave_shlib& shl);
00059 
00060   static void remove (octave_shlib& shl, octave_shlib::close_hook cl_hook = 0);
00061 
00062   static octave_shlib find_file (const std::string& file_name);
00063 
00064   static void display (void);
00065 
00066 private:
00067 
00068   octave_shlib_list (void) : lib_list () { }
00069 
00070   ~octave_shlib_list (void) { }
00071 
00072   void do_append (const octave_shlib& shl);
00073 
00074   void do_remove (octave_shlib& shl, octave_shlib::close_hook cl_hook = 0);
00075 
00076   octave_shlib do_find_file (const std::string& file_name) const;
00077 
00078   void do_display (void) const;
00079 
00080   static octave_shlib_list *instance;
00081 
00082   static void cleanup_instance (void) { delete instance; instance = 0; }
00083 
00084   static bool instance_ok (void);
00085 
00086   // List of libraries we have loaded.
00087   std::list<octave_shlib> lib_list;
00088 
00089   // No copying!
00090 
00091   octave_shlib_list (const octave_shlib_list&);
00092 
00093   octave_shlib_list& operator = (const octave_shlib_list&);
00094 };
00095 
00096 octave_shlib_list *octave_shlib_list::instance = 0;
00097 
00098 void
00099 octave_shlib_list::do_append (const octave_shlib& shl)
00100 {
00101   lib_list.push_back (shl);
00102 }
00103 
00104 void
00105 octave_shlib_list::do_remove (octave_shlib& shl,
00106                               octave_shlib::close_hook cl_hook)
00107 {
00108   for (iterator p = lib_list.begin (); p != lib_list.end (); p++)
00109     {
00110       if (*p == shl)
00111         {
00112           // Erase first to avoid potentially invalidating the pointer by the
00113           // following hooks.
00114           lib_list.erase (p);
00115 
00116           shl.close (cl_hook);
00117 
00118           break;
00119         }
00120     }
00121 }
00122 
00123 octave_shlib
00124 octave_shlib_list::do_find_file (const std::string& file_name) const
00125 {
00126   octave_shlib retval;
00127 
00128   for (const_iterator p = lib_list.begin (); p != lib_list.end (); p++)
00129     {
00130       if (p->file_name () == file_name)
00131         {
00132           retval = *p;
00133           break;
00134         }
00135     }
00136 
00137   return retval;
00138 }
00139 
00140 void
00141 octave_shlib_list::do_display (void) const
00142 {
00143   std::cerr << "current shared libraries:" << std::endl;
00144   for (const_iterator p = lib_list.begin (); p != lib_list.end (); p++)
00145     std::cerr << "  " << p->file_name () << std::endl;
00146 }
00147 
00148 bool
00149 octave_shlib_list::instance_ok (void)
00150 {
00151   bool retval = true;
00152 
00153   if (! instance)
00154     {
00155       instance = new octave_shlib_list ();
00156 
00157       if (instance)
00158         singleton_cleanup_list::add (cleanup_instance);
00159     }
00160 
00161   if (! instance)
00162     {
00163       ::error ("unable to create shared library list object!");
00164 
00165       retval = false;
00166     }
00167 
00168   return retval;
00169 }
00170 
00171 void
00172 octave_shlib_list::append (const octave_shlib& shl)
00173 {
00174   if (instance_ok ())
00175     instance->do_append (shl);
00176 }
00177 
00178 void
00179 octave_shlib_list::remove (octave_shlib& shl,
00180                            octave_shlib::close_hook cl_hook)
00181 {
00182   if (instance_ok ())
00183     instance->do_remove (shl, cl_hook);
00184 }
00185 
00186 octave_shlib
00187 octave_shlib_list::find_file (const std::string& file_name)
00188 {
00189   return (instance_ok ())
00190     ? instance->do_find_file (file_name) : octave_shlib ();
00191 }
00192 
00193 void
00194 octave_shlib_list::display (void)
00195 {
00196   if (instance_ok ())
00197     instance->do_display ();
00198 }
00199 
00200 class
00201 octave_mex_file_list
00202 {
00203 public:
00204 
00205   typedef std::list<octave_shlib>::iterator iterator;
00206   typedef std::list<octave_shlib>::const_iterator const_iterator;
00207 
00208   static void append (const octave_shlib& shl);
00209 
00210   static void remove (octave_shlib& shl, octave_shlib::close_hook cl_hook = 0);
00211 
00212 private:
00213 
00214   octave_mex_file_list (void) : file_list () { }
00215 
00216   ~octave_mex_file_list (void) { }
00217 
00218   void do_append (const octave_shlib& shl);
00219 
00220   void do_remove (octave_shlib& shl, octave_shlib::close_hook cl_hook = 0);
00221 
00222   static octave_mex_file_list *instance;
00223 
00224   static void cleanup_instance (void) { delete instance; instance = 0; }
00225 
00226   static bool instance_ok (void);
00227 
00228   // List of libraries we have loaded.
00229   std::list<octave_shlib> file_list;
00230 
00231   // No copying!
00232 
00233   octave_mex_file_list (const octave_mex_file_list&);
00234 
00235   octave_mex_file_list& operator = (const octave_mex_file_list&);
00236 };
00237 
00238 octave_mex_file_list *octave_mex_file_list::instance = 0;
00239 
00240 void
00241 octave_mex_file_list::do_append (const octave_shlib& shl)
00242 {
00243   file_list.push_back (shl);
00244 }
00245 
00246 void
00247 octave_mex_file_list::do_remove (octave_shlib& shl,
00248                                  octave_shlib::close_hook cl_hook)
00249 {
00250   for (iterator p = file_list.begin (); p != file_list.end (); p++)
00251     {
00252       if (*p == shl)
00253         {
00254           // Erase first to avoid potentially invalidating the pointer by the
00255           // following hooks.
00256           file_list.erase (p);
00257 
00258           shl.close (cl_hook);
00259 
00260           break;
00261         }
00262     }
00263 }
00264 
00265 bool
00266 octave_mex_file_list::instance_ok (void)
00267 {
00268   bool retval = true;
00269 
00270   if (! instance)
00271     {
00272       instance = new octave_mex_file_list ();
00273 
00274       if (instance)
00275         singleton_cleanup_list::add (cleanup_instance);
00276     }
00277 
00278   if (! instance)
00279     {
00280       ::error ("unable to create shared library list object!");
00281 
00282       retval = false;
00283     }
00284 
00285   return retval;
00286 }
00287 
00288 void
00289 octave_mex_file_list::append (const octave_shlib& shl)
00290 {
00291   if (instance_ok ())
00292     instance->do_append (shl);
00293 }
00294 
00295 void
00296 octave_mex_file_list::remove (octave_shlib& shl,
00297                               octave_shlib::close_hook cl_hook)
00298 {
00299   if (instance_ok ())
00300     instance->do_remove (shl, cl_hook);
00301 }
00302 
00303 octave_dynamic_loader *octave_dynamic_loader::instance = 0;
00304 
00305 bool octave_dynamic_loader::doing_load = false;
00306 
00307 bool
00308 octave_dynamic_loader::instance_ok (void)
00309 {
00310   bool retval = true;
00311 
00312   if (! instance)
00313     {
00314       instance = new octave_dynamic_loader ();
00315 
00316       if (instance)
00317         singleton_cleanup_list::add (cleanup_instance);
00318     }
00319 
00320   if (! instance)
00321     {
00322       ::error ("unable to create dynamic loader object!");
00323 
00324       retval = false;
00325     }
00326 
00327   return retval;
00328 }
00329 
00330 static void
00331 do_clear_function (const std::string& fcn_name)
00332 {
00333   warning_with_id ("Octave:reload-forces-clear", "  %s", fcn_name.c_str ());
00334 
00335   symbol_table::clear_dld_function (fcn_name);
00336 }
00337 
00338 static void
00339 clear (octave_shlib& oct_file)
00340 {
00341   if (oct_file.number_of_functions_loaded () > 1)
00342     {
00343       warning_with_id ("Octave:reload-forces-clear",
00344                        "reloading %s clears the following functions:",
00345                        oct_file.file_name().c_str ());
00346 
00347       octave_shlib_list::remove (oct_file, do_clear_function);
00348     }
00349   else
00350     octave_shlib_list::remove (oct_file, symbol_table::clear_dld_function);
00351 }
00352 
00353 octave_function *
00354 octave_dynamic_loader::do_load_oct (const std::string& fcn_name,
00355                                     const std::string& file_name,
00356                                     bool relative)
00357 {
00358   octave_function *retval = 0;
00359 
00360   unwind_protect frame;
00361 
00362   frame.protect_var (octave_dynamic_loader::doing_load);
00363 
00364   doing_load = true;
00365 
00366   octave_shlib oct_file = octave_shlib_list::find_file (file_name);
00367 
00368   if (oct_file && oct_file.is_out_of_date ())
00369     clear (oct_file);
00370 
00371   if (! oct_file)
00372     {
00373       oct_file.open (file_name);
00374 
00375       if (! error_state && oct_file)
00376         octave_shlib_list::append (oct_file);
00377     }
00378 
00379   if (! error_state)
00380     {
00381       if (oct_file)
00382         {
00383           void *function = oct_file.search (fcn_name, name_mangler);
00384 
00385           if (! function)
00386             {
00387               // FIXME -- can we determine this C mangling scheme
00388               // automatically at run time or configure time?
00389 
00390               function = oct_file.search (fcn_name, name_uscore_mangler);
00391             }
00392 
00393           if (function)
00394             {
00395               octave_dld_fcn_getter f
00396                 = FCN_PTR_CAST (octave_dld_fcn_getter, function);
00397 
00398               retval = f (oct_file, relative);
00399 
00400               if (! retval)
00401                 ::error ("failed to install .oct file function '%s'",
00402                          fcn_name.c_str ());
00403             }
00404         }
00405       else
00406         ::error ("%s is not a valid shared library",
00407                  file_name.c_str ());
00408     }
00409 
00410   return retval;
00411 }
00412 
00413 octave_function *
00414 octave_dynamic_loader::do_load_mex (const std::string& fcn_name,
00415                                     const std::string& file_name,
00416                                     bool /*relative*/)
00417 {
00418   octave_function *retval = 0;
00419 
00420   unwind_protect frame;
00421 
00422   frame.protect_var (octave_dynamic_loader::doing_load);
00423 
00424   doing_load = true;
00425 
00426   octave_shlib mex_file = octave_shlib_list::find_file (file_name);
00427 
00428   if (mex_file && mex_file.is_out_of_date ())
00429     clear (mex_file);
00430 
00431   if (! mex_file)
00432     {
00433       mex_file.open (file_name);
00434 
00435       if (! error_state && mex_file)
00436         octave_shlib_list::append (mex_file);
00437     }
00438 
00439   if (! error_state)
00440     {
00441       if (mex_file)
00442         {
00443           void *function = 0;
00444 
00445           bool have_fmex = false;
00446 
00447           octave_mex_file_list::append (mex_file);
00448 
00449           function = mex_file.search (fcn_name, mex_mangler);
00450 
00451           if (! function)
00452             {
00453               // FIXME -- can we determine this C mangling scheme
00454               // automatically at run time or configure time?
00455 
00456               function = mex_file.search (fcn_name, mex_uscore_mangler);
00457 
00458               if (! function)
00459                 {
00460                   function = mex_file.search (fcn_name, mex_f77_mangler);
00461 
00462                   if (function)
00463                     have_fmex = true;
00464                 }
00465             }
00466 
00467           if (function)
00468             retval = new octave_mex_function (function, have_fmex,
00469                                               mex_file, fcn_name);
00470           else
00471             ::error ("failed to install .mex file function '%s'",
00472                      fcn_name.c_str ());
00473         }
00474       else
00475         ::error ("%s is not a valid shared library",
00476                  file_name.c_str ());
00477     }
00478 
00479   return retval;
00480 }
00481 
00482 bool
00483 octave_dynamic_loader::do_remove_oct (const std::string& fcn_name,
00484                                       octave_shlib& shl)
00485 {
00486   bool retval = false;
00487 
00488   // We don't need to do anything if this is called because we are in
00489   // the process of reloading a .oct file that has changed.
00490 
00491   if (! doing_load)
00492     {
00493       retval = shl.remove (fcn_name);
00494 
00495       if (shl.number_of_functions_loaded () == 0)
00496         octave_shlib_list::remove (shl);
00497     }
00498 
00499   return retval;
00500 }
00501 
00502 bool
00503 octave_dynamic_loader::do_remove_mex (const std::string& fcn_name,
00504                                       octave_shlib& shl)
00505 {
00506   bool retval = false;
00507 
00508   // We don't need to do anything if this is called because we are in
00509   // the process of reloading a .oct file that has changed.
00510 
00511   if (! doing_load)
00512     {
00513       retval = shl.remove (fcn_name);
00514 
00515       if (shl.number_of_functions_loaded () == 0)
00516         octave_mex_file_list::remove (shl);
00517     }
00518 
00519   return retval;
00520 }
00521 
00522 octave_function *
00523 octave_dynamic_loader::load_oct (const std::string& fcn_name,
00524                                   const std::string& file_name,
00525                                   bool relative)
00526 {
00527   return (instance_ok ())
00528     ? instance->do_load_oct (fcn_name, file_name, relative) : 0;
00529 }
00530 
00531 octave_function *
00532 octave_dynamic_loader::load_mex (const std::string& fcn_name,
00533                                   const std::string& file_name,
00534                                   bool relative)
00535 {
00536   return (instance_ok ())
00537     ? instance->do_load_mex (fcn_name, file_name, relative) : 0;
00538 }
00539 
00540 bool
00541 octave_dynamic_loader::remove_oct (const std::string& fcn_name,
00542                                    octave_shlib& shl)
00543 {
00544   return (instance_ok ()) ? instance->do_remove_oct (fcn_name, shl) : false;
00545 }
00546 
00547 bool
00548 octave_dynamic_loader::remove_mex (const std::string& fcn_name,
00549                                    octave_shlib& shl)
00550 {
00551   return (instance_ok ()) ? instance->do_remove_mex (fcn_name, shl) : false;
00552 }
00553 
00554 std::string
00555 octave_dynamic_loader::name_mangler (const std::string& name)
00556 {
00557   return "G" + name;
00558 }
00559 
00560 std::string
00561 octave_dynamic_loader::name_uscore_mangler (const std::string& name)
00562 {
00563   return "_G" + name;
00564 }
00565 
00566 std::string
00567 octave_dynamic_loader::mex_mangler (const std::string&)
00568 {
00569   return "mexFunction";
00570 }
00571 
00572 std::string
00573 octave_dynamic_loader::mex_uscore_mangler (const std::string&)
00574 {
00575   return "_mexFunction";
00576 }
00577 
00578 std::string
00579 octave_dynamic_loader::mex_f77_mangler (const std::string&)
00580 {
00581   return STRINGIFY (F77_FUNC (mexfunction, MEXFUNCTION));
00582 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines