From deaf0702e5d8cfcfe82e7acebd1aa6cf13c73aaf Mon Sep 17 00:00:00 2001 From: tchernobog Date: Sat, 16 Sep 2006 11:21:06 +0000 Subject: [PATCH] - Add down_cast<> to safely checking dynamic_casts when in development. Be sure to read its documentation before use\! git-svn-id: svn://svn.gna.org/svn/sgpemv2/trunk@1188 3ecf2c5c-341e-0410-92b4-d18e462d057c --- Makefile.am | 1 + src/backend/concrete_history.cc | 34 +++-- src/backend/sgpemv2/templates/down_cast.tcc | 159 ++++++++++++++++++++ 3 files changed, 178 insertions(+), 16 deletions(-) create mode 100644 src/backend/sgpemv2/templates/down_cast.tcc diff --git a/Makefile.am b/Makefile.am index ba214a1..dcafc7c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -436,6 +436,7 @@ EXTRA_DIST += $(glade_DATA) templates_HEADERS += \ src/backend/sgpemv2/templates/deletor.tcc \ + src/backend/sgpemv2/templates/down_cast.tcc \ src/backend/sgpemv2/templates/parameter.tcc \ src/backend/sgpemv2/templates/sequences.tcc \ src/backend/sgpemv2/templates/singleton.hh \ diff --git a/src/backend/concrete_history.cc b/src/backend/concrete_history.cc index ddd6423..81cfaba 100644 --- a/src/backend/concrete_history.cc +++ b/src/backend/concrete_history.cc @@ -32,9 +32,11 @@ #include "static_request.hh" #include "static_sub_request.hh" -#include #include "concrete_history.hh" +#include + +#include #include #include @@ -170,7 +172,7 @@ ConcreteHistory::remove(resource_key_t resource_key) typedef ConcreteEnvironment::Processes::iterator ProcIt; for (ProcIt it1 = processes.begin(); it1 != processes.end(); it1++) { - Threads& threads = dynamic_cast(**it1).get_dynamic_threads(); + Threads& threads = down_cast(**it1).get_dynamic_threads(); for (Threads::iterator it2 = threads.begin(); it2 != threads.end(); it2++) { Requests& reqs = (*it2)->get_dynamic_requests(); @@ -212,7 +214,7 @@ ConcreteHistory::remove(Process& process) void ConcreteHistory::remove(Thread& thread) { - DynamicThread& dyn_thr = dynamic_cast(thread); + DynamicThread& dyn_thr = down_cast(thread); // Pay attention that initial isn't deleted by reset() ConcreteEnvironment& initial = *_snapshots.front(); @@ -223,7 +225,7 @@ ConcreteHistory::remove(Thread& thread) if (found == NULL) return; // not found, just return. - DynamicProcess& dynamic_found = dynamic_cast(*found); + DynamicProcess& dynamic_found = down_cast(*found); bool removed = deep_remove(dynamic_found.get_dynamic_threads(), dyn_thr); if (removed) @@ -234,7 +236,7 @@ ConcreteHistory::remove(Thread& thread) void ConcreteHistory::remove(Request& request) { - DynamicRequest& dyn_req = dynamic_cast(request); + DynamicRequest& dyn_req = down_cast(request); DynamicThread& dyn_thr = dyn_req.get_thread(); DynamicProcess& dyn_proc = dyn_thr.get_process(); @@ -243,7 +245,7 @@ ConcreteHistory::remove(Request& request) ConcreteEnvironment::Processes& processes = initial.get_processes(); Process* proc_ref = deep_find(processes, dyn_proc); - DynamicProcess* dyn_proc_ref = dynamic_cast(proc_ref); + DynamicProcess* dyn_proc_ref = down_cast(proc_ref); if (dyn_proc_ref == NULL) return; // not found, just return. DynamicThread* thr_ref = deep_find(dyn_proc_ref->get_dynamic_threads(), dyn_thr); @@ -263,7 +265,7 @@ ConcreteHistory::remove(SubRequest& subrequest) // this function makes one relevant assumption: // the initial environment does contain empty request queues only. - DynamicSubRequest& dyn_sub = dynamic_cast(subrequest); + DynamicSubRequest& dyn_sub = down_cast(subrequest); DynamicRequest& dyn_req = dyn_sub.get_request(); DynamicThread& dyn_thr = dyn_req.get_thread(); DynamicProcess& dyn_proc = dyn_thr.get_process(); @@ -273,7 +275,7 @@ ConcreteHistory::remove(SubRequest& subrequest) ConcreteEnvironment::Processes& processes = initial.get_processes(); Process* proc_ref = deep_find(processes, dyn_proc); - DynamicProcess* dyn_proc_ref = dynamic_cast(proc_ref); + DynamicProcess* dyn_proc_ref = down_cast(proc_ref); if (dyn_proc_ref == NULL) return; // not found, just return. DynamicThread* thr_ref = deep_find(dyn_proc_ref->get_dynamic_threads(), dyn_thr); @@ -346,7 +348,7 @@ ConcreteHistory::edit_resource(Resource& resource, { // And preemptable and availability?? FIXME! - DynamicResource* res = dynamic_cast(&resource); + DynamicResource* res = down_cast(&resource); StaticResource& core = res->get_core(); core.set_name(name); core.set_places(places); @@ -379,7 +381,7 @@ ConcreteHistory::edit_process(Process& process, time_t arrival_time, prio_t base_priority) { - DynamicProcess* proc = dynamic_cast(&process); + DynamicProcess* proc = down_cast(&process); StaticProcess& core = proc->get_core(); core.set_name(name); core.set_arrival_time(arrival_time); @@ -399,7 +401,7 @@ ConcreteHistory::add_thread(const Glib::ustring& name, { reset(false); - DynamicProcess& parent_process = dynamic_cast(parent); + DynamicProcess& parent_process = down_cast(parent); StaticProcess& parent_core = parent_process.get_core(); StaticThread* core = new StaticThread(name, parent_core, cpu_time, arrival_time, base_priority); DynamicThread* thread = new DynamicThread(core, &parent_process); @@ -415,7 +417,7 @@ ConcreteHistory::edit_thread(Thread& thread, time_t arrival_time, prio_t base_priority) { - DynamicThread* thre = dynamic_cast(&thread); + DynamicThread* thre = down_cast(&thread); StaticThread& core = thre->get_core(); core.set_name(name); core.set_total_cpu_time(cpu_time); @@ -431,7 +433,7 @@ ConcreteHistory::add_request(Thread& owner, { reset(false); - DynamicThread& dyn_owner = dynamic_cast(owner); + DynamicThread& dyn_owner = down_cast(owner); StaticThread& owner_core = dyn_owner.get_core(); StaticRequest* core = new StaticRequest(&owner_core, instant); @@ -447,7 +449,7 @@ void ConcreteHistory::edit_request(Request& request, time_t instant) { - DynamicRequest* req = dynamic_cast(&request); + DynamicRequest* req = down_cast(&request); StaticRequest& core = req->get_core(); core.set_instant(instant); @@ -462,7 +464,7 @@ ConcreteHistory::add_subrequest(Request& request, { reset(false); - DynamicRequest& dyn_request = dynamic_cast(request); + DynamicRequest& dyn_request = down_cast(request); StaticSubRequest* core = new StaticSubRequest(resource_key, duration); DynamicSubRequest* subreq = new DynamicSubRequest(core, &dyn_request); @@ -478,7 +480,7 @@ ConcreteHistory::edit_subrequest(SubRequest& subrequest, resource_key_t resource_key, time_t duration) { - DynamicSubRequest* sreq = dynamic_cast(&subrequest); + DynamicSubRequest* sreq = down_cast(&subrequest); StaticSubRequest& core = sreq->get_core(); core.set_resource_key(resource_key); core.set_length(duration); diff --git a/src/backend/sgpemv2/templates/down_cast.tcc b/src/backend/sgpemv2/templates/down_cast.tcc new file mode 100644 index 0000000..2453fdb --- /dev/null +++ b/src/backend/sgpemv2/templates/down_cast.tcc @@ -0,0 +1,159 @@ +// sgpemv2/templates/down_cast.tcc - Copyright 2005, 2006, University +// of Padova, dept. of Pure and Applied +// Mathematics +// +// This file is part of SGPEMv2. +// +// This is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// SGPEMv2 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with SGPEMv2; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +#ifndef DOWN_CAST_TCC +#define DOWN_CAST_TCC 1 + +#include + +#ifndef NDEBUG +#include +#include +#include +#include +#endif + +namespace sgpem +{ + /** \brief A debug functor that wraps C++ dynamic_cast + * + * Since we may want to debug exceptions easily before + * the stack becomes unwinded, this functor wraps + * the normal C++ dynamic_cast<> for references and: + * + * - if the macro NDEBUG isn't defined, and the + * dynamic_cast<> throws a std::bad_cast exception, + * suspend the process so that the debugger can + * immediately get a backtrace; + * - else, use a static_cast. This is meant for + * release code that has been \strong extensively + * tested. + * + * This template comes in two partial specializations: + * one for references, and one for pointers. + * + * Note that you shouldn't use \strong always this + * template for all your downcast, but only for those + * you don't want to test their return value because + * you assume it's correct. + */ + template + struct _down_cast + { + // Uninstantiable for normal objects. + // Partial specializations for references and pointers + // will follow. + + // We use a functor, and not a normal template function, + // because in this way the parameter of operator() + // is automatically deduced by the compiler (else we + // would have to provide two template parameters), and + // we've an extra type-check that we aren't using + // normal objects as template parameters, but + // just pointers or references. + }; + + // -------------------------------------- + // Specialization for references: + + template + struct _down_cast + { + template + inline To& operator()(From& obj) const + { +#ifndef NDEBUG + try + { + return dynamic_cast(obj); + } + catch(const std::bad_cast& e) + { + pid_t me = getpid(); + std::clog << "DEBUG: st8ad_cast exception. " + << "Guru Meditation #81310005.48454C50." << std::endl + << " ** " << e.what() << std::endl + << "Process [" << me << "] stopped." << std::endl; + kill(me, SIGSTOP); + throw; + } +#else + return static_cast(obj); +#endif + } + }; + + // -------------------------------------- + // Specialization for pointers: + + template + struct _down_cast + { + template + inline To* operator()(From* obj) const + { +#ifndef NDEBUG + To* check_ptr = dynamic_cast(obj); + if(check_ptr == NULL) + { + pid_t me = getpid(); + std::clog << "DEBUG: dynamic_cast<> returned null pointer. " + << "Guru Meditation #81310005.48454C50." << std::endl + << "Process [" << me << "] stopped." << std::endl; + kill(me, SIGSTOP); + throw; + } + return check_ptr; +#else + return dynamic_cast(obj); +#endif + } + }; + + /** \brief Helper function to check a downcast for references + * + * See ::_down_cast for a more extensive documentation. This + * is just a wrapper to provide a more natural interface to + * the user + */ + template + inline To down_cast(From& obj) + { + return _down_cast()(obj); + } + + /** \brief Helper function to check a downcast for pointers + * + * See ::_down_cast for a more extensive documentation. This + * is just a wrapper to provide a more natural interface to + * the user + */ + template + inline To down_cast(From* const obj) + { + return _down_cast()(obj); + } + + +} //~ namespace sgpem + +#endif //~ DOWN_CAST_TCC +