| 1 | /* | 
|---|
| 2 | * CRTDLL exit/abort/atexit functions | 
|---|
| 3 | * | 
|---|
| 4 | * Copyright 1996,1998 Marcus Meissner | 
|---|
| 5 | * Copyright 1996 Jukka Iivonen | 
|---|
| 6 | * Copyright 1997,2000 Uwe Bonnes | 
|---|
| 7 | * Copyright 2000 Jon Griffiths | 
|---|
| 8 | * | 
|---|
| 9 | * exit functions differ in whether they perform cleanup | 
|---|
| 10 | * and whether they return to the caller (really!). | 
|---|
| 11 | *            return      do | 
|---|
| 12 | *  Name      to caller?  cleanup? | 
|---|
| 13 | *  _c_exit     Y           N | 
|---|
| 14 | *  _cexit      Y           Y | 
|---|
| 15 | *  _exit       N           N | 
|---|
| 16 | *  exit        N           Y | 
|---|
| 17 | * | 
|---|
| 18 | * Implementation Notes: | 
|---|
| 19 | * Not MT Safe - Adding/Executing exit() functions should be locked | 
|---|
| 20 | * for MT safety. | 
|---|
| 21 | * | 
|---|
| 22 | * FIXME: | 
|---|
| 23 | * Need a better way of printing errors for GUI programs(MsgBox?). | 
|---|
| 24 | * Is there really a difference between onexit/atexit? | 
|---|
| 25 | */ | 
|---|
| 26 | #include "crtdll.h" | 
|---|
| 27 | #include <errno.h> | 
|---|
| 28 | #include "process.h" | 
|---|
| 29 |  | 
|---|
| 30 |  | 
|---|
| 31 | DEFAULT_DEBUG_CHANNEL(crtdll); | 
|---|
| 32 |  | 
|---|
| 33 | /* INTERNAL: Table of registered atexit() functions */ | 
|---|
| 34 | /* FIXME: This should be dynamically allocated */ | 
|---|
| 35 | #define CRTDLL_ATEXIT_TABLE_SIZE 16 | 
|---|
| 36 |  | 
|---|
| 37 | static atexit_function atexit_table[CRTDLL_ATEXIT_TABLE_SIZE]; | 
|---|
| 38 | static int atexit_registered = 0; /* Points to free slot */ | 
|---|
| 39 |  | 
|---|
| 40 |  | 
|---|
| 41 | /* INTERNAL: call atexit functions */ | 
|---|
| 42 | void __CRTDLL__call_atexit(VOID); | 
|---|
| 43 | void __CRTDLL__call_atexit(VOID) | 
|---|
| 44 | { | 
|---|
| 45 | /* Last registered gets executed first */ | 
|---|
| 46 | while (atexit_registered > 0) | 
|---|
| 47 | { | 
|---|
| 48 | atexit_registered--; | 
|---|
| 49 | TRACE(":call function (%p)\n",atexit_table[atexit_registered]); | 
|---|
| 50 | (*atexit_table[atexit_registered])(); | 
|---|
| 51 | } | 
|---|
| 52 | } | 
|---|
| 53 |  | 
|---|
| 54 |  | 
|---|
| 55 | /********************************************************************* | 
|---|
| 56 | *      __dllonexit                             (CRTDLL.25) | 
|---|
| 57 | */ | 
|---|
| 58 | VOID CDECL CRTDLL___dllonexit () | 
|---|
| 59 | { | 
|---|
| 60 | dprintf(("__dllonexit not implemented.\n")); | 
|---|
| 61 | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | 
|---|
| 62 | } | 
|---|
| 63 |  | 
|---|
| 64 |  | 
|---|
| 65 | /********************************************************************* | 
|---|
| 66 | *      _abnormal_termination                   (CRTDLL.36) | 
|---|
| 67 | */ | 
|---|
| 68 | int CDECL CRTDLL__abnormal_termination(void) | 
|---|
| 69 | { | 
|---|
| 70 | dprintf(("CRTDLL: _abnormal_termination  not implemented.\n")); | 
|---|
| 71 | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | 
|---|
| 72 | return FALSE;  /* FIXME: Can we determine if we are in an exception? */ | 
|---|
| 73 | } | 
|---|
| 74 |  | 
|---|
| 75 |  | 
|---|
| 76 | /********************************************************************* | 
|---|
| 77 | *                  _amsg_exit     (CRTDLL.040) | 
|---|
| 78 | * | 
|---|
| 79 | * Print an error message and terminate execution. Returns 255 to the | 
|---|
| 80 | * host OS. | 
|---|
| 81 | */ | 
|---|
| 82 | VOID CDECL CRTDLL__amsg_exit(int errnum) | 
|---|
| 83 | { | 
|---|
| 84 | dprintf2(("CRTDLL: _amsg_exit\n")); | 
|---|
| 85 |  | 
|---|
| 86 | // fprintf(stderr,strerror(errnum)); | 
|---|
| 87 | // ExitProcess(-1); | 
|---|
| 88 |  | 
|---|
| 89 | CRTDLL_fprintf(CRTDLL_stderr,"\nrun-time error:\nError Code %d\n",errnum); | 
|---|
| 90 | CRTDLL__exit(255); | 
|---|
| 91 | } | 
|---|
| 92 |  | 
|---|
| 93 |  | 
|---|
| 94 | /********************************************************************* | 
|---|
| 95 | *                  _assert     (CRTDLL.041) | 
|---|
| 96 | * | 
|---|
| 97 | * Print an assertion message and call abort(). Really only present | 
|---|
| 98 | * for win binaries. Winelib programs would typically use libc's | 
|---|
| 99 | * version. | 
|---|
| 100 | */ | 
|---|
| 101 | VOID CDECL CRTDLL__assert(LPVOID str, LPVOID file, UINT line) | 
|---|
| 102 | { | 
|---|
| 103 | dprintf2(("CRTDLL: _assert\n")); | 
|---|
| 104 |  | 
|---|
| 105 | CRTDLL_fprintf(CRTDLL_stderr,"Assertion failed: %s, file %s, line %d\n\n", | 
|---|
| 106 | (char*)str,(char*)file, line); | 
|---|
| 107 | CRTDLL_abort(); | 
|---|
| 108 |  | 
|---|
| 109 | // _assert(str, file, line); | 
|---|
| 110 | } | 
|---|
| 111 |  | 
|---|
| 112 |  | 
|---|
| 113 | /********************************************************************* | 
|---|
| 114 | *                  _c_exit           (CRTDLL.047) | 
|---|
| 115 | * @@@PH verify if argument ret is correct, or void is correct (WINE) | 
|---|
| 116 | */ | 
|---|
| 117 | VOID CDECL CRTDLL__c_exit(INT ret) | 
|---|
| 118 | { | 
|---|
| 119 | dprintf2(("_c_exit(%d)\n",ret)); | 
|---|
| 120 | FIXME("not calling CRTDLL cleanup\n"); | 
|---|
| 121 |  | 
|---|
| 122 | /* dont exit, return to caller */ | 
|---|
| 123 |  | 
|---|
| 124 | ExitProcess(ret); | 
|---|
| 125 | } | 
|---|
| 126 |  | 
|---|
| 127 |  | 
|---|
| 128 | /********************************************************************* | 
|---|
| 129 | *                  _cexit           (CRTDLL.049) | 
|---|
| 130 | * @@@PH verify if argument ret is correct, or void is correct (WINE) | 
|---|
| 131 | */ | 
|---|
| 132 | VOID CDECL CRTDLL__cexit(INT ret) | 
|---|
| 133 | { | 
|---|
| 134 | dprintf2(("_cexit(%d)\n",ret)); | 
|---|
| 135 | FIXME("not calling CRTDLL cleanup\n"); | 
|---|
| 136 | /* dont exit, return to caller */ | 
|---|
| 137 |  | 
|---|
| 138 | ExitProcess(ret); | 
|---|
| 139 | } | 
|---|
| 140 |  | 
|---|
| 141 |  | 
|---|
| 142 | /********************************************************************* | 
|---|
| 143 | *                  _exit           (CRTDLL.087) | 
|---|
| 144 | */ | 
|---|
| 145 | VOID CDECL CRTDLL__exit(LONG ret) | 
|---|
| 146 | { | 
|---|
| 147 | dprintf2(("CRTDLL: _exit (%08xh)\n", | 
|---|
| 148 | ret)); | 
|---|
| 149 | TRACE(":exit code %ld\n",ret); | 
|---|
| 150 | CRTDLL__c_exit(ret); | 
|---|
| 151 | ExitProcess(ret); | 
|---|
| 152 | } | 
|---|
| 153 |  | 
|---|
| 154 |  | 
|---|
| 155 | /********************************************************************* | 
|---|
| 156 | *                  _onexit           (CRTDLL.236) | 
|---|
| 157 | * | 
|---|
| 158 | * Register a function to be called when the process terminates. | 
|---|
| 159 | */ | 
|---|
| 160 | atexit_function CDECL CRTDLL__onexit( atexit_function func) | 
|---|
| 161 | { | 
|---|
| 162 | TRACE("registering function (%p)\n",func); | 
|---|
| 163 | if (func && atexit_registered <= CRTDLL_ATEXIT_TABLE_SIZE - 1) | 
|---|
| 164 | { | 
|---|
| 165 | atexit_table[atexit_registered] = (atexit_function)func; | 
|---|
| 166 | atexit_registered++; | 
|---|
| 167 | return func; /* successful */ | 
|---|
| 168 | } | 
|---|
| 169 | ERR(":Too many onexit() functions, or NULL function - not registered!\n"); | 
|---|
| 170 | return NULL; | 
|---|
| 171 |  | 
|---|
| 172 | // onexit_t CDECL CRTDLL__onexit(onexit_t t) | 
|---|
| 173 | // { | 
|---|
| 174 | //   dprintf2(("CRTDLL: _onexit\n")); | 
|---|
| 175 | //   return (_onexit(t)); | 
|---|
| 176 | // } | 
|---|
| 177 | } | 
|---|
| 178 |  | 
|---|
| 179 |  | 
|---|
| 180 | /********************************************************************* | 
|---|
| 181 | *                  exit          (CRTDLL.359) | 
|---|
| 182 | */ | 
|---|
| 183 | VOID CDECL CRTDLL_exit(DWORD ret) | 
|---|
| 184 | { | 
|---|
| 185 | TRACE(":exit code %ld\n",ret); | 
|---|
| 186 | __CRTDLL__call_atexit(); | 
|---|
| 187 | CRTDLL__cexit(ret); | 
|---|
| 188 | ExitProcess(ret); | 
|---|
| 189 | } | 
|---|
| 190 |  | 
|---|
| 191 |  | 
|---|
| 192 | /********************************************************************* | 
|---|
| 193 | *                   abort     (CRTDLL.335) | 
|---|
| 194 | * | 
|---|
| 195 | * Terminate the progam with an abnormal termination message. Returns | 
|---|
| 196 | * 3 to the host OS. | 
|---|
| 197 | */ | 
|---|
| 198 | VOID CDECL CRTDLL_abort() | 
|---|
| 199 | { | 
|---|
| 200 | dprintf2(("CRTDLL: abort\n")); | 
|---|
| 201 |  | 
|---|
| 202 | CRTDLL_fprintf(CRTDLL_stderr,"\nabnormal program termination\n"); | 
|---|
| 203 | CRTDLL__exit(3); | 
|---|
| 204 | //abort(); | 
|---|
| 205 | } | 
|---|
| 206 |  | 
|---|
| 207 |  | 
|---|
| 208 | /********************************************************************* | 
|---|
| 209 | *                  atexit      (CRTDLL.342) | 
|---|
| 210 | * | 
|---|
| 211 | * Register a function to be called when the process terminates. | 
|---|
| 212 | */ | 
|---|
| 213 | INT CDECL CRTDLL_atexit(void (*func)(void)) | 
|---|
| 214 | { | 
|---|
| 215 | dprintf(("CRTDLL: atexit\n")); | 
|---|
| 216 |  | 
|---|
| 217 | return CRTDLL__onexit(func) == func ? 0 : -1; | 
|---|
| 218 |  | 
|---|
| 219 | // if (_atexit_n >= sizeof (_atexit_v) / sizeof (_atexit_v[0])) | 
|---|
| 220 | //   return -1; | 
|---|
| 221 | // _atexit_v[_atexit_n++] = func; | 
|---|
| 222 | // return 0; | 
|---|
| 223 | } | 
|---|
| 224 |  | 
|---|
| 225 |  | 
|---|
| 226 | /********************************************************************* | 
|---|
| 227 | *                  _aexit_rtn_dll    (CRTDLL.39) | 
|---|
| 228 | */ | 
|---|
| 229 | VOID CDECL CRTDLL__aexit_rtn_dll(int exitcode) | 
|---|
| 230 | { | 
|---|
| 231 | dprintf2(("CRTDLL: _aexit_rtn_dll\n")); | 
|---|
| 232 | ExitProcess(exitcode); | 
|---|
| 233 | } | 
|---|
| 234 |  | 
|---|