24 Oct 13:25
Re: Boost Exception and support for cloning
Anthony Williams <anthony_w.geo <at> yahoo.com>
2007-10-24 11:25:42 GMT
2007-10-24 11:25:42 GMT
"Josh Napoli" <jnapoli <at> actuality-systems.com> writes: >> Mathias Gaunard wrote: >> C++0x has virtual constructors? > > No - but exceptions (only) will get a special built-in clone mechanism > (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html) I have an implementation of this for MSVC which I intended to upload soon for boost.thread, once I'd got a generic (and thus incomplete) version working. Source code attached. Anthony -- Anthony Williams Just Software Solutions Ltd - http://www.justsoftwaresolutions.co.uk Registered in England, Company Number 5478976. Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL
// Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // (C) Copyright 2007 Anthony Williams #ifndef EXCEPTION_PTR_HPP #define EXCEPTION_PTR_HPP #include <typeinfo> #include "thread_heap_alloc.hpp" #include <string.h> #include "thread_primitives.hpp" #include <excpt.h> namespace jss { namespace detail { namespace win32 { unsigned const exception_maximum_parameters=15; unsigned const exception_noncontinuable=1; struct exception_record { unsigned long ExceptionCode; unsigned long ExceptionFlags; exception_record *ExceptionRecord; void* ExceptionAddress; unsigned long NumberParameters; ulong_ptr ExceptionInformation[exception_maximum_parameters]; }; struct exception_pointers { exception_record* ExceptionRecord; void* ContextRecord; }; extern "C" { __declspec(dllimport) void __stdcall RaiseException(unsigned long,unsigned long,unsigned long,ulong_ptr*); } } unsigned const cpp_exception_code=0xE06D7363; unsigned const cpp_exception_magic_flag=0x19930520; unsigned const cpp_exception_parameter_count=3; struct dummy_exception_type {}; typedef int(dummy_exception_type::*normal_copy_constructor_ptr)(void* src); typedef int(dummy_exception_type::*copy_constructor_with_virtual_base_ptr)(void* src,void* dest); typedef void (dummy_exception_type::*destructor_ptr)(); union cpp_copy_constructor { normal_copy_constructor_ptr normal_copy_constructor; copy_constructor_with_virtual_base_ptr copy_constructor_with_virtual_base; }; enum cpp_type_flags{ class_is_simple_type=1, class_has_virtual_base=4 }; struct cpp_type_info { unsigned flags; std::type_info* type_info; int this_offset; int vbase_descr; int vbase_offset; unsigned long size; cpp_copy_constructor copy_constructor; }; struct cpp_type_info_table { unsigned count; const cpp_type_info* info[1]; }; struct cpp_exception_type { unsigned flags; destructor_ptr destructor; void(*custom_handler)(); const cpp_type_info_table* type_info_table; }; struct cloned_exception { cpp_exception_type const* exception_type; void* exception_object; bool run_destructor; long count; cloned_exception(cloned_exception const& other): exception_type(other.exception_type), exception_object(0), count(0), run_destructor(false) { clone(other.exception_object); } void clone(void* source_object) { exception_object=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,exception_type->type_info_table->info[0]->size); const cpp_type_info *type = exception_type->type_info_table->info[0]; if(!(type->flags & class_is_simple_type) && type->copy_constructor.normal_copy_constructor) { dummy_exception_type* dummy_exception_ptr=reinterpret_cast<dummy_exception_type*>(exception_object); if(type->flags & class_has_virtual_base) { (dummy_exception_ptr->*(type->copy_constructor.copy_constructor_with_virtual_base))(source_object,exception_object); } else { (dummy_exception_ptr->*(type->copy_constructor.normal_copy_constructor))(source_object); } } else { memmove(exception_object,source_object,type->size); } run_destructor=true; } cloned_exception(void* source_object,cpp_exception_type const* exception_type_): exception_type(exception_type_), exception_object(0), count(0), run_destructor(false) { clone(source_object); } ~cloned_exception() { if(exception_object) { if(run_destructor) { dummy_exception_type* dummy_exception_ptr=reinterpret_cast<dummy_exception_type*>(exception_object); (dummy_exception_ptr->*(exception_type->destructor))(); } detail::win32::HeapFree(win32::GetProcessHeap(),0,exception_object); } } void rethrow() { cloned_exception temp(*this); detail::win32::ulong_ptr args[detail::cpp_exception_parameter_count]; args[0]=detail::cpp_exception_magic_flag; args[1]=reinterpret_cast<detail::win32::ulong_ptr>(temp.exception_object); args[2]=reinterpret_cast<detail::win32::ulong_ptr>(temp.exception_type); temp.run_destructor=false; detail::win32::RaiseException(detail::cpp_exception_code,detail::win32::exception_noncontinuable,detail::cpp_exception_parameter_count,args); } friend void intrusive_ptr_add_ref(cloned_exception * p) { JSS_INTERLOCKED_INCREMENT(&p->count); } friend void intrusive_ptr_release(cloned_exception * p) { if(!JSS_INTERLOCKED_DECREMENT(&p->count)) { detail::heap_delete(p); } } }; } typedef boost::intrusive_ptr<detail::cloned_exception> exception_ptr; namespace detail { extern "C" int* _errno(); bool is_cpp_exception(win32::exception_record* record) { return record && (record->ExceptionCode==cpp_exception_code) && (record->NumberParameters==cpp_exception_parameter_count) && (record->ExceptionInformation[0]==cpp_exception_magic_flag); } unsigned long exception_cloning_filter(exception_ptr* ptr,void* info_) { win32::exception_pointers* info=reinterpret_cast<win32::exception_pointers*>(info_); win32::exception_record* record=info->ExceptionRecord; if(is_cpp_exception(record)) { if(!record->ExceptionInformation[2]) { #if _MSC_VER==1310 unsigned const exception_info_offset=0x74; #elif _MSC_VER==1400 unsigned const exception_info_offset=0x80; #endif record=*reinterpret_cast<win32::exception_record**≥(reinterpret_cast<char*>(_errno())+exception_info_offset); } if(is_cpp_exception(record) && record->ExceptionInformation[2]) { *ptr=detail::heap_new<cloned_exception>(reinterpret_cast<void*>(record->ExceptionInformation[1]), reinterpret_cast<cpp_exception_type const*>(record->ExceptionInformation[2])); } } return EXCEPTION_EXECUTE_HANDLER; } void clone_current_exception(exception_ptr* res) { __try { throw; } __except(exception_cloning_filter(res,GetExceptionInformation())) { } } } inline exception_ptr current_exception() { exception_ptr res; clone_current_exception(&res); return res; } inline void rethrow_exception(exception_ptr p) { if(p) { p->rethrow(); } else { throw "no exception stored"; } } template<class E> exception_ptr copy_exception(E e) { try { throw e; } catch( ... ) { return current_exception(); } } } #endif
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
RSS Feed