View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0002213 | Scribus | Internal | public | 2005-07-09 21:35 | 2005-11-03 12:59 |
Reporter | jghali | Assigned To | jghali | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | closed | Resolution | fixed | ||
Platform | Windows | OS | Windows | OS Version | 2000 SP4 |
Product Version | 1.3.0cvs | ||||
Fixed in Version | 1.3.2cvs | ||||
Summary | 0002213: mscv compatibility for main.cpp | ||||
Description | The attached diff allow main.cpp to compile on msvc. It deals with signals management. Most of the functions used (sigemptyset, sigaddset, sigprocmask...) are non existent on win32 and have no equivalent. I have looked at libgw32c to see how these functions were implemented. But define dummy functions and it's about the same. So it's what I've done... Just replaced the alarm() one ... If someone has a better solution... (It may exists : http://www.cs.wustl.edu/~schmidt/ACE.html ) | ||||
Tags | No tags attached. | ||||
Patch | |||||
|
Only affects win32, and looks ok except for a missing #ifdef _WIN32 around the VOID CALLBACK implementation. Merging. |
|
Actually, I'll hold on this one and see what cbradney thinks - he might have an alternative to suggest. I'm not comfortable with just merging anything that #defines away functions, especially since those are not protected by #ifdef _WIN32 . |
|
Reminder sent to: cbradney Any thoughts on this one? I'm wondering if providing an alternative implementation for the body of the function doing all the setup might be better. |
|
If the signals dont exist then they wont be sent. Better to not undefine and find a different solution. I will look at this today. |
|
/*************************************************************************** main.cpp - description ------------------- begin : Fre Apr 6 21:47:55 CEST 2001 copyright : (C) 2001 by Franz Schmid email : Franz.Schmid@altmuehlnet.de copyright : (C) 2004 by Alessandro Rimoldi email : http://ideale.ch/contact copyright : (C) 2005 by Craig Bradney email : cbradney@zip.com.au ***************************************************************************/ /*************************************************************************** * * * This program 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. * * * ***************************************************************************/ #include <iostream> #include <signal.h> #include <qapplication.h> #define BASE_QM "scribus" #include "scribusapp.h" #include "scribus.h" #include "scconfig.h" #ifdef _WIN32 #include <windows.h> #ifndef SIG_UNBLOCK #define SIG_UNBLOCK 2 #endif #ifndef SIGALRM #define SIGALRM 14 #endif #ifndef sigset_t #define sigset_t int #endif #ifndef sigemptyset #define sigemptyset(sig) #endif #ifndef sigaddset #define sigaddset( set, sig) #endif #ifndef sigprocmask #define sigprocmask(a, b, c) #endif VOID CALLBACK raiseSigAlarm(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime); #define alarm(delay) SetTimer(NULL, NULL, delay, (TIMERPROC) raiseSigAlarm) #endif int mainApp(int argc, char **argv); void initCrashHandler(); static void defaultCrashHandler(int sig); ScribusApp* ScApp; ScribusQApp* ScQApp; bool emergencyActivated; int main(int argc, char *argv[]) { return mainApp(argc, argv); } /*! \fn int mainGui(int argc, char **argv) \author Franz Schmid \author Alessandro Rimoldi \author Craig Bradney \date Mon Feb 9 14:07:46 CET 2004 \brief Launches the Gui \param int Number of arguments passed to Scribus \param char *argv list of the arguments passed to Scribus \retval int Error code from the execution of Scribus */ int mainApp(int argc, char **argv) { emergencyActivated=false; ScribusQApp app(argc, argv); initCrashHandler(); app.parseCommandLine(); if (app.usingGUI()) { int appRetVal=app.init(); if (appRetVal==EXIT_FAILURE) return(EXIT_FAILURE); return app.exec(); } return EXIT_SUCCESS; } void initCrashHandler() { typedef void (*HandlerType)(int); HandlerType handler = 0; handler = defaultCrashHandler; if (!handler) handler = SIG_DFL; sigset_t mask; sigemptyset(&mask); #ifdef SIGSEGV signal (SIGSEGV, handler); sigaddset(&mask, SIGSEGV); #endif #ifdef SIGFPE signal (SIGFPE, handler); sigaddset(&mask, SIGFPE); #endif #ifdef SIGILL signal (SIGILL, handler); sigaddset(&mask, SIGILL); #endif #ifdef SIGABRT signal (SIGABRT, handler); sigaddset(&mask, SIGABRT); #endif sigprocmask(SIG_UNBLOCK, &mask, 0); } void defaultCrashHandler(int sig) { static int crashRecursionCounter = 0; crashRecursionCounter++; signal(SIGALRM, SIG_DFL); if (crashRecursionCounter < 2) { emergencyActivated=true; crashRecursionCounter++; QString sigHdr=QObject::tr("Scribus Crash"); QString sigLine="-------------"; QString sigMsg=QObject::tr("Scribus crashes due to Signal #%1").arg(sig); std::cout << sigHdr << std::endl; std::cout << sigLine << std::endl; std::cout << sigMsg << std::endl; if (ScribusQApp::useGUI) { ScApp->closeSplash(); QMessageBox::critical(ScApp, sigHdr, sigMsg, QObject::tr("&OK")); ScApp->emergencySave(); ScApp->close(); } alarm(300); } exit(255); } #ifdef _WIN32 VOID CALLBACK raiseSigAlarm(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { raise(SIGALRM); } #endif |
|
As I said, if you have a better solution, I'll take it. |
|
I dont at this point in time. Is there a call to be made to hook up the signal in Windows? like: typedef void (*HandlerType)(int); HandlerType handler = 0; handler = defaultCrashHandler; in our current code? That seems to be missing if so. Ringerc said he might have an idea re splitting it into a different function on Windows. At this points its probably sufficiently uncomplicated enough to not worry, but a tidier solution might be found. |
|
I'm looking on my side. To my knowledge, the closest thing to what you mention requires use of MFC api. For a taste a the thing : http://www.codeproject.com/dialog/messagehandling.asp http://www.codeproject.com/dialog/messagehandling2.asp Another thing... MFC... Beuaahhh!!! POSIX style signal handling is quite minimal on Windows and is not availaible with Win32 api, only through C RTL. Here are the signal management functions defined in msvc signal.h - int raise(int sig); - void (__cdecl *signal(int sig, void (__cdecl *func )(int[,int ])))(int); That's all... |
|
Here are interesting threads : http://archives.postgresql.org/pgsql-hackers-win32/2004-01/msg00003.php http://archives.postgresql.org/pgsql-hackers-win32/2004-01/msg00069.php |
|
Asking myself if we need to crash our head about this subject, as SIGSEGV, SIGFPE, SIGILL and SIGABRT (etc...) are by default unblocked on win32... I've already observed a crash with message "Scribus crashes due to Signal 11" on my win32 build. If signals need to be blocked on win32, CriticalSection can be used... |
|
Apparently on win32, exit() should not be called from a signal handler. So win32 defaultCrashHandler should be modified. Thinking to something like this : - remove line signal(SIGALRM, SIG_DFL) - remove line exit(255) Then modify raiseSigAlarm(): - use exit() or SendMessage(hwnd, WM_CLOSE, ...) instead of raise() - rename raiseSigAlarm into something more meaningful Comments??? |
|
Additionnaly, on win32, SIGINT is not supported for Win32 application. See : http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_CRT_signal.asp The Win32 release build will be compiled with _WINDOWS directive and standard streams redirected to display in a debug window. |
|
Additionnaly, according to msdn, the SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows NT. They are included for ANSI compatibility and should be raised explicitly. |
|
I think I've found a satisfying crash handler for win32. Instead of using exit() in defaultCrashHandler it throws a runtime_error exception which is catched in main(). It works on win32, does it on *nix? The modified main has been uploaded (main_except.cpp). Additionnaly, some info about signal handling on win32 : signal handlers are never inherited by child processes. So on win32, all sigaddset, sigemptyset, sigprocmask are not useful in this case. |
|
Qt on some (most?) Linux distros is compiled without exceptions. Additionally, Scribus isn't really ready to be built with exception support (a *lot* of 'new' calls need to be changed to new (nothrow) ... or fixed up, for example). Personally, I don't know *why* as I came from the Python world were excepions are something utterly fundamental, but it seems a lot of C++ folks don't like them and think they cause memory bloat. It's not a debate I'm really intersted in getting into, and I don't know the right answer. I'm not sure, however, that relying on exceptions for core error handling is wise given that some vendors will just turn it off. I don't know much about C++ exceptions. Can we safely work with a Qt built without exceptions when we enable exceptions? Will we pay a big penalty in memory consumption from exceptions or has that been cleaned up in more recentlt compilers? |
|
A quick chat on the #KDE suggests that exceptions, at least with gcc, are more acceptable efficiency-wise than they used to be. Apparently they're OK to use with code that doesn't support exceptions so long as you don't throw exceptions "through" code - such as the Qt event loop - that doesn't understand them. I presume that'll be because that code won't have the appropriate compiler-generated code for detecting the exception, cleaning up, and returning properly. This means that they're likely to be OK for things like void doSomethingBig() { try ... long list of statements ... catch something ... and clean up } but probably *not* for transferring control around large bits of the program. In addition to not throwing through the Qt event loop I think we'd also have to watch out for throwing through signal/slot dispatch, which given Scribus's heavy use of signals and slots even when simple function calls are more appropriate would be a serious problem. |
|
Hum... Going to find another way of doing the thing then... |
|
I've done a little more reading on the use of exceptions on win32. It looks like win32 uses its underlying structured exception handling (SEH) mechanism to implement C++ exceptions. Since SEH is used to handle things like segmentation violations, it looks like they extended the C++ exception support to permit you to "catch" a segfault, etc. This won't work on Linux, as the implementation of exceptions in gcc is different, and doesn't map the POSIX signals the OS uses to inform apps about such problems to exceptions. It may be possible to use SEH on win32 to handle these conditions, without going for full C++ exception support. Here's some info on SEH, in case it's useful: http://www.microsoft.com/msj/0197/exception/exception.aspx |
|
I have coded a new main.cpp (main_win.cpp) using structured exceptions. Seems to work well. Will test further before submiting. |
2005-11-02 22:02
|
main_win.cpp (6,877 bytes)
/*************************************************************************** main.cpp - description ------------------- begin : Fre Apr 6 21:47:55 CEST 2001 copyright : (C) 2001 by Franz Schmid email : Franz.Schmid@altmuehlnet.de copyright : (C) 2004 by Alessandro Rimoldi email : http://ideale.ch/contact copyright : (C) 2005 by Craig Bradney email : cbradney@zip.com.au ***************************************************************************/ /*************************************************************************** * * * This program 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. * * * ***************************************************************************/ #include <iostream> #include <signal.h> #ifndef _WIN32 #error "This file compiles on win32 platform only" #endif #include <qapplication.h> #include <exception> using namespace std; #define BASE_QM "scribus" #include "scribusapp.h" #include "scribus.h" #include "scconfig.h" #include <windows.h> int mainApp(ScribusQApp& app); static LONG exceptionFilter(DWORD exceptionCode); static QString exceptionDescription(DWORD exceptionCode); static void defaultCrashHandler(DWORD exceptionCode); ScribusApp SCRIBUS_API *ScApp; ScribusQApp SCRIBUS_API *ScQApp; bool emergencyActivated; int main(int argc, char *argv[]) { int result; emergencyActivated = false; ScribusQApp app(argc, argv); result = mainApp(app); return result; } /*! \fn int mainApp(ScribusQApp& app) \author Franz Schmid \author Alessandro Rimoldi \author Craig Bradney \author Jean Ghali \date Mon Feb 9 14:07:46 CET 2004 \brief Launches the Gui \param ScribusQApp& app a Scribus QApplication object \retval int Error code from the execution of Scribus */ int mainApp(ScribusQApp& app) { int appRetVal; __try { app.parseCommandLine(); if (app.usingGUI()) { appRetVal = app.init(); if (appRetVal != EXIT_FAILURE) appRetVal = app.exec(); } } __except( exceptionFilter(GetExceptionCode()) ) { defaultCrashHandler( GetExceptionCode() ); } return appRetVal; } /*! \fn int exceptionFilter(DWORD exceptionCode) \author Jean Ghali \date Sun Oct 30 14:30:30 CET 2005 \brief describe the behavior to be adopted against specific exception \param DWORD exceptionCode the value returned by GetExceptionCode() \retval EXCEPTION_EXECUTE_HANDLER if handler is to be executed or EXCEPTION_CONTINUE_EXECUTION if not */ LONG exceptionFilter(DWORD exceptionCode) { LONG result; switch( exceptionCode ) { case EXCEPTION_ACCESS_VIOLATION: case EXCEPTION_DATATYPE_MISALIGNMENT: case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: case EXCEPTION_FLT_DENORMAL_OPERAND: case EXCEPTION_FLT_DIVIDE_BY_ZERO: case EXCEPTION_FLT_INEXACT_RESULT: case EXCEPTION_FLT_INVALID_OPERATION: case EXCEPTION_FLT_OVERFLOW: case EXCEPTION_FLT_STACK_CHECK: case EXCEPTION_FLT_UNDERFLOW: case EXCEPTION_ILLEGAL_INSTRUCTION: case EXCEPTION_INT_DIVIDE_BY_ZERO: case EXCEPTION_INT_OVERFLOW: case EXCEPTION_INVALID_HANDLE: case EXCEPTION_NONCONTINUABLE_EXCEPTION: case EXCEPTION_STACK_OVERFLOW: result = EXCEPTION_EXECUTE_HANDLER; break; case EXCEPTION_BREAKPOINT: case EXCEPTION_SINGLE_STEP: result = EXCEPTION_CONTINUE_EXECUTION; break; default: result = EXCEPTION_EXECUTE_HANDLER; break; } return result; } /*! \fn int exceptionDescription(DWORD exceptionCode) \author Jean Ghali \date Sun Oct 30 14:30:30 CET 2005 \brief return a string describing a specific exception \param DWORD exceptionCode the value returned by GetExceptionCode() \retval string describing the specified exception */ static QString exceptionDescription(DWORD exceptionCode) { QString description; if ( exceptionCode == EXCEPTION_ACCESS_VIOLATION ) description = "EXCEPTION_ACCESS_VIOLATION"; else if ( exceptionCode == EXCEPTION_DATATYPE_MISALIGNMENT ) description = "EXCEPTION_DATATYPE_MISALIGNMENT"; else if ( exceptionCode == EXCEPTION_ARRAY_BOUNDS_EXCEEDED ) description = "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; else if ( exceptionCode == EXCEPTION_FLT_DENORMAL_OPERAND ) description = "EXCEPTION_FLT_DENORMAL_OPERAND"; else if ( exceptionCode == EXCEPTION_FLT_DIVIDE_BY_ZERO ) description = "EXCEPTION_FLT_DIVIDE_BY_ZERO"; else if ( exceptionCode == EXCEPTION_FLT_INEXACT_RESULT ) description = "EXCEPTION_FLT_INEXACT_RESULT"; else if ( exceptionCode == EXCEPTION_FLT_INVALID_OPERATION ) description = "EXCEPTION_FLT_INVALID_OPERATION"; else if ( exceptionCode == EXCEPTION_FLT_OVERFLOW ) description = "EXCEPTION_FLT_OVERFLOW"; else if ( exceptionCode == EXCEPTION_FLT_STACK_CHECK ) description = "EXCEPTION_FLT_STACK_CHECK"; else if ( exceptionCode == EXCEPTION_FLT_UNDERFLOW ) description = "EXCEPTION_FLT_UNDERFLOW"; else if ( exceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION ) description = "EXCEPTION_ILLEGAL_INSTRUCTION"; else if ( exceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO ) description = "EXCEPTION_INT_DIVIDE_BY_ZERO"; else if ( exceptionCode == EXCEPTION_INT_OVERFLOW ) description = "EXCEPTION_INT_OVERFLOW"; else if ( exceptionCode == EXCEPTION_INVALID_HANDLE ) description = "EXCEPTION_INVALID_HANDLE"; else if ( exceptionCode == EXCEPTION_NONCONTINUABLE_EXCEPTION ) description = "EXCEPTION_NONCONTINUABLE_EXCEPTION"; else if ( exceptionCode == EXCEPTION_STACK_OVERFLOW ) description = "EXCEPTION_STACK_OVERFLOW"; else description = "UNKNOWN EXCEPTION"; return description; } void defaultCrashHandler(DWORD exceptionCode) { static int crashRecursionCounter = 0; crashRecursionCounter++; if (crashRecursionCounter < 2) { emergencyActivated=true; crashRecursionCounter++; QString expDesc = exceptionDescription(exceptionCode); QString expHdr=QObject::tr("Scribus Crash"); QString expLine="-------------"; QString expMsg=QObject::tr("Scribus crashes due to the following exception : %1").arg(expDesc); std::cout << (const char*) expHdr << std::endl; std::cout << (const char*) expLine << std::endl; std::cout << (const char*) expMsg << std::endl; if (ScribusQApp::useGUI) { ScApp->closeSplash(); QMessageBox::critical(ScApp, expHdr, expMsg, QObject::tr("&OK")); ScApp->emergencySave(); ScApp->close(); } } ExitProcess(255); } |
|
I've uploaded the new main for windows (main_win.cpp). |
Date Modified | Username | Field | Change |
---|---|---|---|
2005-07-09 21:35 | jghali | New Issue | |
2005-07-09 21:35 | jghali | File Added: main_signals_13x.diff | |
2005-07-10 02:30 |
|
Note Added: 0005474 | |
2005-07-10 02:35 |
|
Note Added: 0005475 | |
2005-07-10 02:35 |
|
Status | new => acknowledged |
2005-07-10 02:36 |
|
Note Added: 0005476 | |
2005-07-10 04:16 | cbradney | Note Added: 0005486 | |
2005-07-10 04:17 | cbradney | Status | acknowledged => assigned |
2005-07-10 04:17 | cbradney | Assigned To | => cbradney |
2005-07-10 07:41 | cbradney | Note Added: 0005488 | |
2005-07-10 07:46 | jghali | Note Added: 0005489 | |
2005-07-10 09:24 | cbradney | Note Added: 0005492 | |
2005-07-10 11:16 | jghali | Note Added: 0005493 | |
2005-07-10 11:25 | jghali | Note Added: 0005494 | |
2005-07-10 12:07 | jghali | Note Edited: 0005494 | |
2005-07-10 18:05 | jghali | Note Added: 0005498 | |
2005-07-15 07:40 |
|
Relationship added | related to 0000015 |
2005-07-15 07:41 |
|
Relationship replaced | child of 0000015 |
2005-07-18 20:12 | jghali | Note Added: 0005636 | |
2005-07-18 21:32 | jghali | Note Edited: 0005636 | |
2005-07-18 21:34 | jghali | Note Edited: 0005636 | |
2005-07-19 07:05 | jghali | Note Added: 0005639 | |
2005-07-19 11:42 | jghali | Note Added: 0005640 | |
2005-07-23 21:03 | jghali | File Added: main_except.cpp | |
2005-07-23 21:16 | jghali | Note Added: 0005678 | |
2005-07-24 06:09 |
|
Note Added: 0005686 | |
2005-07-24 06:17 |
|
Note Added: 0005687 | |
2005-07-24 13:51 | jghali | Note Added: 0005694 | |
2005-08-30 11:55 | cbradney | Assigned To | cbradney => jghali |
2005-10-29 08:01 |
|
Note Added: 0007249 | |
2005-10-30 14:53 | jghali | Note Added: 0007267 | |
2005-11-02 22:02 | jghali | File Added: main_win.cpp | |
2005-11-02 22:02 | jghali | File Deleted: main_signals_13x.diff | |
2005-11-02 22:02 | jghali | File Deleted: main_except.cpp | |
2005-11-02 22:04 | jghali | Note Added: 0007312 | |
2005-11-02 22:10 | jghali | Note Edited: 0007312 | |
2005-11-03 00:23 | cbradney | Status | assigned => resolved |
2005-11-03 00:23 | cbradney | Fixed in Version | => 1.3.2cvs |
2005-11-03 00:23 | cbradney | Resolution | open => fixed |
2005-11-03 12:59 | jghali | Status | resolved => closed |