Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 45.6% 115 / 0 / 252
Functions: 53.8% 21 / 0 / 39
Branches: 37.0% 51 / 0 / 138

OMCompiler/SimulationRuntime/c/util/omc_error.c
Line Branch Exec Source
1 /*
2 * This file belongs to the OpenModelica Run-Time System
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC), c/o Linköpings
5 * universitet, Department of Computer and Information Science, SE-58183 Linköping, Sweden. All rights
6 * reserved.
7 *
8 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE
9 * AGPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8. ANY
10 * USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S
11 * ACCEPTANCE OF THE BSD NEW LICENSE OR THE OSMC PUBLIC LICENSE OR THE AGPL
12 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
13 *
14 * The OpenModelica software and the OSMC (Open Source Modelica Consortium) Public License
15 * (OSMC-PL) are obtained from OSMC, either from the above address, from the URLs:
16 * http://www.openmodelica.org or https://github.com/OpenModelica/ or
17 * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica distribution. GNU
18 * AGPL version 3 is obtained from: https://www.gnu.org/licenses/licenses.html#GPL. The BSD NEW
19 * License is obtained from: http://www.opensource.org/licenses/BSD-3-Clause.
20 *
21 * This program is distributed WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY
23 * SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF
24 * OSMC-PL.
25 *
26 */
27
28 #include "setjmp.h"
29 #include <stdio.h>
30 #include "omc_error.h"
31 #include <string.h>
32 #include "omc_init.h"
33 #include "simulation_options.h"
34
35 const FILE_INFO omc_dummyFileInfo = omc_dummyFileInfo_val;
36
37 void (*omc_assert)(threadData_t*,FILE_INFO info,const char *msg,...) = omc_assert_function;
38 void (*omc_assert_warning)(FILE_INFO info,const char *msg,...) = omc_assert_warning_function;
39 void (*omc_terminate)(FILE_INFO info,const char *msg,...) = omc_terminate_function;
40 void (*omc_throw)(threadData_t*) __attribute__ ((noreturn)) = omc_throw_function;
41
42 /* An error raised from code that got no threadData (ModelicaError, an external
43 function's assert) finds it through mmc_thread_data_key. Without it there is no
44 jump buffer to leave through, so report and exit rather than crash. The key
45 comes up empty when the executable or an external library linked its own copy
46 of the pthread library: each copy keeps its own thread-specific values. */
47 ✗ threadData_t* omc_thread_data(threadData_t *threadData, const char *pendingMessage)
48 {
49 ✗ if (threadData) {
50 return threadData;
51 }
52 ✗ threadData = (threadData_t*)pthread_getspecific(mmc_thread_data_key);
53 ✗ if (threadData) {
54 return threadData;
55 }
56 ✗ if (pendingMessage) {
57 ✗ fprintf(stderr, "%s\n", pendingMessage);
58 }
59 ✗ fputs("Internal error: the calling thread has no OpenModelica thread data, so the error "
60 "cannot be handled and the simulation is aborted.\n"
61 "This happens when the simulation executable or an external library links its "
62 "own copy of the pthread library (e.g. a static libwinpthread) instead of the "
63 "one the OpenModelica runtime uses.\n", stderr);
64 ✗ fflush(NULL);
65 ✗ exit(1);
66 }
67
68
69 const int firstOMCErrorStream = 1;
70
71 const char *OMC_LOG_STREAM_NAME[OMC_SIM_LOG_MAX] = {
72 "LOG_UNKNOWN",
73 "LOG_STDOUT",
74 "LOG_ASSERT",
75
76 "LOG_DASSL",
77 "LOG_DASSL_STATES",
78 "LOG_DEBUG",
79 "LOG_DELAY",
80 "LOG_DIVISION",
81 "LOG_DSS",
82 "LOG_DSS_JAC",
83 "LOG_DT",
84 "LOG_DT_CONS",
85 "LOG_EVENTS",
86 "LOG_EVENTS_V",
87 "LOG_GBODE",
88 "LOG_GBODE_V",
89 "LOG_GBODE_NLS",
90 "LOG_GBODE_NLS_V",
91 "LOG_GBODE_STATES",
92 "LOG_INIT",
93 "LOG_INIT_HOMOTOPY",
94 "LOG_INIT_V",
95 "LOG_IPOPT",
96 "LOG_IPOPT_FULL",
97 "LOG_IPOPT_JAC",
98 "LOG_IPOPT_HESSE",
99 "LOG_IPOPT_ERROR",
100 "LOG_JAC",
101 "LOG_LS",
102 "LOG_LS_V",
103 "LOG_MIXED",
104 "LOG_MOO",
105 "LOG_NLS",
106 "LOG_NLS_V",
107 "LOG_NLS_HOMOTOPY",
108 "LOG_NLS_JAC",
109 "LOG_NLS_JAC_TEST",
110 "LOG_NLS_JAC_SUMS",
111 "LOG_NLS_NEWTON_DIAGNOSTICS",
112 "LOG_NLS_DERIVATIVE_TEST",
113 "LOG_NLS_SVD",
114 "LOG_NLS_SVD_V",
115 "LOG_NLS_RES",
116 "LOG_NLS_EXTRAPOLATE",
117 "LOG_RES_INIT",
118 "LOG_RT",
119 "LOG_SIMULATION",
120 "LOG_SOLVER",
121 "LOG_SOLVER_V",
122 "LOG_SOLVER_CONTEXT",
123 "LOG_SOTI",
124 "LOG_SPATIALDISTR",
125 "LOG_STATS",
126 "LOG_STATS_V",
127 "LOG_SUCCESS",
128 "LOG_SYNCHRONOUS",
129 "LOG_ZEROCROSSINGS",
130 };
131
132 const char *OMC_LOG_STREAM_DESC[OMC_SIM_LOG_MAX] = {
133 "unknown",
134 "this stream is always active, can be disabled with -lv=-LOG_STDOUT", /* OMC_LOG_STDOUT */
135 "this stream is always active, can be disabled with -lv=-LOG_ASSERT", /* OMC_LOG_ASSERT */
136
137 "additional information about dassl solver", /* OMC_LOG_DASSL */
138 "outputs the states at every dassl call", /* OMC_LOG_DASSL_STATES */
139 "additional debug information", /* OMC_LOG_DEBUG */
140 "debug information for delay operator", /* OMC_LOG_DELAY */
141 "Log division by zero", /* OMC_LOG_DIVISION */
142 "outputs information about dynamic state selection", /* OMC_LOG_DSS */
143 "outputs jacobian of the dynamic state selection", /* OMC_LOG_DSS_JAC */
144 "additional information about dynamic tearing", /* OMC_LOG_DT */
145 "additional information about dynamic tearing (local and global constraints)",/* OMC_LOG_DT_CONS */
146 "additional information during event iteration", /* OMC_LOG_EVENTS */
147 "verbose logging of event system", /* OMC_LOG_EVENTS_V */
148 "information about GBODE solver", /* OMC_LOG_GBODE */
149 "verbose information about GBODE solver", /* OMC_LOG_GBODE_V */
150 "log non-linear solver process of GBODE solver", /* OMC_LOG_GBODE_NLS */
151 "verbose log non-linear solver process of GBODE solver", /* OMC_LOG_GBODE_NLS_V */
152 "output states at every GBODE call", /* OMC_LOG_GBODE_STATES */
153 "additional information during initialization", /* OMC_LOG_INIT */
154 "log homotopy initialization", /* OMC_LOG_INIT_HOMOTOPY */
155 "verbose information during initialization", /* OMC_LOG_INIT_V */
156 "information from Ipopt", /* OMC_LOG_IPOPT */
157 "more information from Ipopt", /* OMC_LOG_IPOPT_FULL*/
158 "check jacobian matrix with Ipopt", /* OMC_LOG_IPOPT_JAC*/
159 "check hessian matrix with Ipopt", /* OMC_LOG_IPOPT_HESSE*/
160 "print max error in the optimization", /* OMC_LOG_IPOPT_ERROR*/
161 "outputs the jacobian matrix used by ODE solvers", /* OMC_LOG_JAC */
162 "logging for linear systems", /* OMC_LOG_LS */
163 "verbose logging of linear systems", /* OMC_LOG_LS_V */
164 "logging for mixed systems", /* OMC_LOG_MIXED */
165 "logging for dynamic optimization library MOO", /* OMC_LOG_MOO */
166 "logging for nonlinear systems", /* OMC_LOG_NLS */
167 "verbose logging of nonlinear systems", /* OMC_LOG_NLS_V */
168 "logging of homotopy solver for nonlinear systems", /* OMC_LOG_NLS_HOMOTOPY */
169 "outputs the jacobian of nonlinear systems", /* OMC_LOG_NLS_JAC */
170 "tests the analytical jacobian of nonlinear systems", /* OMC_LOG_NLS_JAC_TEST */
171 "tests the absolute sums of rows and cols in Kinsol Jacobian", /* OMC_LOG_NLS_JAC_SUMS */
172 "newton diagnostics (see: https://doi.org/10.1016/j.amc.2021.125991)", /* OMC_LOG_NLS_NEWTON_DIAGNOSTICS */
173 "test derivatives in KINSOL nonlinear systems", /* OMC_LOG_NLS_DERIVATIVE_TEST */
174 "perform a SVD analysis in KINSOL nonlinear systems", /* OMC_LOG_NLS_SVD */
175 "perform a SVD analysis in KINSOL nonlinear systems (verbose)", /* OMC_LOG_NLS_SVD_V */
176 "outputs every evaluation of the residual function", /* OMC_LOG_NLS_RES */
177 "outputs debug information about extrapolate process", /* OMC_LOG_NLS_EXTRAPOLATE */
178 "outputs residuals of the initialization", /* OMC_LOG_RES_INIT */
179 "additional information regarding real-time processes", /* OMC_LOG_RT */
180 "additional information about simulation process", /* OMC_LOG_SIMULATION */
181 "additional information about solver process", /* OMC_LOG_SOLVER */
182 "verbose information about the integration process", /* OMC_LOG_SOLVER_V */
183 "context information during the solver process", /* OMC_LOG_SOLVER_CONTEXT" */
184 "final solution of the initialization", /* OMC_LOG_SOTI */
185 "logging of internal operations for spatialDistribution", /* OMC_LOG_SPATIALDISTR */
186 "additional statistics about timer/events/solver", /* OMC_LOG_STATS */
187 "additional statistics for OMC_LOG_STATS", /* OMC_LOG_STATS_V */
188 "this stream is always active, unless deactivated with -lv=-LOG_SUCCESS", /* OMC_LOG_SUCCESS */
189 "log clocks and sub-clocks for synchronous features", /* OMC_LOG_SYNCHRONOUS */
190 "additional information about the zerocrossings" /* OMC_LOG_ZEROCROSSINGS */
191 };
192
193 const char *OMC_LOG_TYPE_DESC[OMC_LOG_TYPE_MAX] = {
194 "unknown",
195 "info",
196 "warning",
197 "error",
198 "assert",
199 "debug"
200 };
201
202 int omc_useStream[OMC_SIM_LOG_MAX]; /* 1 if LOG is enabled, otherwise 0 */
203 static int backupUseStream[OMC_SIM_LOG_MAX]; /* Backup of omc_useStream */
204 static int omc_level[OMC_SIM_LOG_MAX];
205 static int omc_lastType[OMC_SIM_LOG_MAX];
206 static int omc_lastStream = OMC_LOG_UNKNOWN;
207 int omc_showAllWarnings = 0;
208 static int streamsActive = 1; /* 1 if info streams from omc_useStream are active, 0 if deactivated */
209
210 1 void initDumpSystem(void)
211 {
212 int i;
213
214
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 1 time.
58 for(i=0; i<OMC_SIM_LOG_MAX; ++i)
215 {
216 57 omc_useStream[i] = 0;
217 57 omc_level[i] = 0;
218 57 omc_lastType[i] = 0;
219 }
220
221 1 omc_useStream[OMC_LOG_STDOUT] = 1;
222 1 omc_useStream[OMC_LOG_ASSERT] = 1;
223 1 omc_useStream[OMC_LOG_SUCCESS] = 1;
224 1 }
225
226 /* Deactivates streams for logging except for stdout, assert and success. */
227 ✗ void deactivateLogging(void)
228 {
229 int i;
230
231 ✗ if (streamsActive == 0)
232 {
233 return; /* Do nothing if already inactive */
234 }
235
236 ✗ for(i=0; i<OMC_SIM_LOG_MAX; ++i)
237 {
238 ✗ if (i != OMC_LOG_STDOUT && i != OMC_LOG_ASSERT && i != OMC_LOG_SUCCESS)
239 {
240 ✗ backupUseStream[i] = omc_useStream[i];
241 /*
242 if (omc_useStream[i] != 0) {
243 printf("Stream %s deactivated\n",LOG_STREAM_NAME[i]);
244 }
245 */
246 ✗ omc_useStream[i] = 0;
247 }
248 }
249
250 ✗ omc_useStream[OMC_LOG_STDOUT] = 1;
251 ✗ omc_useStream[OMC_LOG_ASSERT] = 1;
252 ✗ omc_useStream[OMC_LOG_SUCCESS] = 1;
253
254 ✗ streamsActive = 0; /* Deactivate info streams */
255 //infoStreamPrint(OMC_LOG_STDOUT,0,"Deactivated logging");
256 }
257
258 /* Resets streams to backup after deactivateLogging() was used. */
259 ✗ void reactivateLogging(void)
260 {
261 int i;
262
263 ✗ if (streamsActive == 1)
264 {
265 return; /* Do nothing if already active */
266 }
267
268 ✗ for(i=0; i<OMC_SIM_LOG_MAX; ++i)
269 {
270 ✗ if (i != OMC_LOG_STDOUT && i != OMC_LOG_ASSERT && i != OMC_LOG_SUCCESS)
271 {
272 ✗ omc_useStream[i] = backupUseStream[i];
273 /*
274 if (omc_useStream[i] != 0) {
275 printf("Stream %s reactivated\n",LOG_STREAM_NAME[i]);
276 }
277 */
278 }
279 }
280
281 ✗ streamsActive = 1; /* Activate info streams */
282 //infoStreamPrint(OMC_LOG_STDOUT,0,"Reactivated logging");
283 }
284
285 ✗ void printInfo(FILE *stream, FILE_INFO info)
286 {
287 ✗ fprintf(stream, "[%s:%d:%d-%d:%d:%s]", info.filename, info.lineStart, info.colStart, info.lineEnd, info.colEnd, info.readonly ? "readonly" : "writable");
288 ✗ }
289
290 static void (*omc_assert_reporter)(threadData_t*, FILE_INFO, const char*, va_list) = NULL;
291 static void (*omc_assert_warning_reporter)(FILE_INFO, const char*, va_list) = NULL;
292
293 114 void omc_set_assert_reporters(void (*err)(threadData_t*, FILE_INFO, const char*, va_list),
294 void (*warn)(FILE_INFO, const char*, va_list))
295 {
296 114 omc_assert_reporter = err;
297 114 omc_assert_warning_reporter = warn;
298 114 }
299
300 ✗ void omc_assert_function(threadData_t* threadData, FILE_INFO info, const char *msg, ...)
301 {
302 va_list ap;
303 ✗ va_start(ap,msg);
304 ✗ if (omc_assert_reporter) {
305 ✗ omc_assert_reporter(threadData, info, msg, ap);
306 } else {
307 ✗ printInfo(stderr, info);
308 ✗ fputs("Modelica Assert: ", stderr);
309 ✗ vfprintf(stderr,msg,ap);
310 ✗ fputs("!\n", stderr);
311 }
312 ✗ va_end(ap);
313 ✗ fflush(NULL);
314 ✗ threadData = omc_thread_data(threadData, NULL);
315 ✗ OMC_ERROR_RAISE();
316 ✗ }
317
318 ✗ void omc_assert_warning_function(FILE_INFO info, const char *msg, ...)
319 {
320 va_list ap;
321 ✗ va_start(ap,msg);
322 ✗ if (omc_assert_warning_reporter) {
323 ✗ omc_assert_warning_reporter(info, msg, ap);
324 } else {
325 ✗ printInfo(stderr, info);
326 ✗ fputs("Warning, assertion triggered: ", stderr);
327 ✗ vfprintf(stderr,msg,ap);
328 ✗ fputs("!\n", stderr);
329 }
330 ✗ va_end(ap);
331 ✗ fflush(NULL);
332 ✗ }
333
334 ✗ void omc_throw_function(threadData_t *threadData)
335 {
336 /* Unlike a model's assert this jumps: it ends the run, and no generated frame
337 is on the stack to owe a release. */
338 ✗ threadData = omc_thread_data(threadData, NULL);
339 ✗ OMC_THROW_INTERNAL();
340 }
341
342 ✗ void omc_terminate_function(FILE_INFO info, const char *msg, ...)
343 {
344 va_list ap;
345 ✗ va_start(ap,msg);
346 ✗ printInfo(stderr, info);
347 ✗ fputs("Modelica Terminate: ", stderr);
348 ✗ vfprintf(stderr,msg,ap);
349 ✗ fputs("!\n", stderr);
350 ✗ va_end(ap);
351 ✗ fflush(NULL);
352 ✗ omc_throw_function(NULL);
353 }
354
355 65 void messageText(int type, int stream, FILE_INFO info, int indentNext, char *msg, int subline, const int *indexes)
356 {
357 int i;
358 int len;
359
360
5/6
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 46 times.
65 printf("%-17s | ", (subline || (omc_lastStream == stream && omc_level[stream] > 0)) ? "|" : OMC_LOG_STREAM_NAME[stream]);
361
6/8
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 54 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 46 times.
65 printf("%-7s | ", (subline || (omc_lastStream == stream && omc_lastType[stream] == type && omc_level[stream] > 0)) ? "|" : OMC_LOG_TYPE_DESC[type]);
362 65 omc_lastType[stream] = type;
363 65 omc_lastStream = stream;
364
365
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 65 times.
139 for(i=0; i<omc_level[stream]; ++i)
366 printf("| ");
367
368
2/4
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 65 times.
65 if (info.filename && strlen(info.filename) > 0) {
369 // Print to stdout because we are using printf down below as well.
370 ✗ printInfo(stdout, info);
371 printf("\n");
372
373 printf("%-17s | ", "|");
374 printf("%-7s | ", "|");
375 }
376
377
2/2
✓ Branch 0 taken 2203 times.
✓ Branch 1 taken 65 times.
2268 for(i=0; msg[i]; i++)
378 {
379
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2203 times.
2203 if(msg[i] == '\n')
380 {
381 ✗ msg[i] = '\0';
382 printf("%s\n", msg);
383 ✗ if (msg[i+1]) {
384 ✗ messageText(type, stream, omc_dummyFileInfo, 0, &msg[i+1], 1, indexes);
385 }
386 ✗ return;
387 }
388 }
389
390 65 len = strlen(msg);
391
2/4
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 65 times.
65 if (len>0 && msg[len-1]=='\n') {
392 printf("%s", msg);
393 } else {
394 printf("%s\n", msg);
395 }
396 65 fflush(NULL);
397
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 48 times.
65 if (indentNext) omc_level[stream]++;
398 }
399
400 /**
401 * @brief Close messages.
402 *
403 * Use for active streams to reduce level of indentation by one.
404 *
405 * @param stream Log stream.
406 */
407 177 static void messageCloseText(int stream)
408 {
409
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 160 times.
177 if(OMC_ACTIVE_STREAM(stream)) {
410 17 omc_level[stream]--;
411 }
412 177 }
413
414 /**
415 * @brief Close warning messages.
416 *
417 * Use for warning messages that indented the stream either because the stream is active
418 * or showAllWarnings is true.
419 *
420 * @param stream Log stream.
421 */
422 ✗ static void messageCloseTextWarning(int stream)
423 {
424 ✗ if (OMC_ACTIVE_WARNING_STREAM(stream)) {
425 ✗ omc_level[stream]--;
426 }
427 ✗ }
428
429 void (*messageFunction)(int type, int stream, FILE_INFO info, int indentNext, char *msg, int subline, const int *indexes) = messageText;
430 /**
431 * @brief Close messages.
432 * See messageCloseText() for more info.
433 */
434 void (*messageClose)(int stream) = messageCloseText;
435 /**
436 * @brief Close warning messages.
437 * See messageCloseTextWarning() for more info.
438 */
439 void (*messageCloseWarning)(int stream) = messageCloseTextWarning;
440
441 #define SIZE_LOG_BUFFER 2048
442
443 #if !defined(OMC_MINIMAL_LOGGING)
444 27 void va_infoStreamPrint(int stream, int indentNext, const char *format, va_list args)
445 {
446
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 if (omc_useStream[stream]) {
447 char logBuffer[SIZE_LOG_BUFFER];
448 vsnprintf(logBuffer, SIZE_LOG_BUFFER, format, args);
449 27 messageFunction(OMC_LOG_TYPE_INFO, stream, omc_dummyFileInfo, indentNext, logBuffer, 0, NULL);
450 }
451 27 }
452
453 9 void infoStreamPrintWithEquationIndexes(int stream, FILE_INFO info, int indentNext, const int *indexes, const char *format, ...)
454 {
455
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (omc_useStream[stream]) {
456 char logBuffer[SIZE_LOG_BUFFER];
457 va_list args;
458 9 va_start(args, format);
459 vsnprintf(logBuffer, SIZE_LOG_BUFFER, format, args);
460 9 va_end(args);
461 9 messageFunction(OMC_LOG_TYPE_INFO, stream, info, indentNext, logBuffer, 0, indexes);
462 }
463 9 }
464
465 29336980 void infoStreamPrint(int stream, int indentNext, const char *format, ...)
466 {
467
2/2
✓ Branch 0 taken 360 times.
✓ Branch 1 taken 29336620 times.
29336980 if (omc_useStream[stream]) {
468 char logBuffer[SIZE_LOG_BUFFER];
469 va_list args;
470 360 va_start(args, format);
471 vsnprintf(logBuffer, SIZE_LOG_BUFFER, format, args);
472 360 va_end(args);
473 360 messageFunction(OMC_LOG_TYPE_INFO, stream, omc_dummyFileInfo, indentNext, logBuffer, 0, NULL);
474 }
475 29336980 }
476
477 27 void warningStreamPrintWithEquationIndexes(int stream, FILE_INFO info, int indentNext, const int *indexes, const char *format, ...)
478 {
479
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
27 if (OMC_ACTIVE_WARNING_STREAM(stream)) {
480 char logBuffer[SIZE_LOG_BUFFER];
481 va_list args;
482 ✗ va_start(args, format);
483 vsnprintf(logBuffer, SIZE_LOG_BUFFER, format, args);
484 ✗ va_end(args);
485 ✗ messageFunction(OMC_LOG_TYPE_WARNING, stream, info, indentNext, logBuffer, 0, indexes);
486 }
487 27 }
488
489 /**
490 * @brief Print warning to stream until limit is reached.
491 *
492 * If `nDisplayed` is larger than user specified display limit for warnings
493 * a info is displayed and no warning will be printed.
494 *
495 * @param stream Stream to print to.
496 * @param indentNext Will increase indentation level by one if true.
497 * @param nDisplayed Number of times this warning was displayed.
498 * @param maxWarnDisplays Maximum allowed warning displays.
499 * @param format Format string with message to print.
500 * @param ... Arguments for format string.
501 */
502 ✗ void warningStreamPrintWithLimit(int stream, int indentNext, unsigned long nDisplayed, unsigned long maxWarnDisplays, const char *format, ...) {
503
504 ✗ if (!OMC_ACTIVE_WARNING_STREAM(stream)) {
505 ✗ return;
506 }
507
508 va_list args;
509
510 /* Display warning */
511 ✗ if (nDisplayed <= maxWarnDisplays) {
512 ✗ va_start(args, format);
513 ✗ va_warningStreamPrint(stream, indentNext, format, args);
514 }
515 ✗ if (nDisplayed == maxWarnDisplays) {
516 ✗ warningStreamPrintLimitReached(stream, indentNext, maxWarnDisplays);
517 }
518 }
519
520 /**
521 * @brief Tell that a repeated warning reached its display limit.
522 *
523 * For a warning that is displayed with its own sublines, so it cannot use
524 * warningStreamPrintWithLimit.
525 *
526 * @param stream Stream of warning.
527 * @param indentNext Will increase indentation level by one if true.
528 * @param maxWarnDisplays Maximum allowed warning displays.
529 */
530 ✗ void warningStreamPrintLimitReached(int stream, int indentNext, unsigned long maxWarnDisplays) {
531 ✗ infoStreamPrint(stream, indentNext, "Too many warnings, reached display limit of %lu. "
532 "Suppressing further warning messages of the same type.", maxWarnDisplays);
533 ✗ infoStreamPrint(stream, indentNext, "Change limit with simulation flag -%s=<newLimit>", FLAG_NAME[FLAG_LV_MAX_WARN]);
534 ✗ }
535
536 /**
537 * @brief Print warning to stream.
538 *
539 * Prints message only if stream is active or global variable showAllWarnings is true.
540 *
541 * Use messageCloseWarning to close message, if indentNext is true.
542 *
543 * @param stream Stream to print to.
544 * @param indentNext Will increase indentation level by one if true.
545 * @param format Format string with message to print.
546 * @param ... Arguments for format string.
547 */
548 6 void warningStreamPrint(int stream, int indentNext, const char *format, ...)
549 {
550
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
6 if (OMC_ACTIVE_WARNING_STREAM(stream)) {
551 char logBuffer[SIZE_LOG_BUFFER];
552 va_list args;
553 4 va_start(args, format);
554 vsnprintf(logBuffer, SIZE_LOG_BUFFER, format, args);
555 4 va_end(args);
556 4 messageFunction(OMC_LOG_TYPE_WARNING, stream, omc_dummyFileInfo, indentNext, logBuffer, 0, NULL);
557 }
558 6 }
559
560 ✗ void va_warningStreamPrintWithEquationIndexes(int stream, FILE_INFO info, int indentNext, const int *indexes, const char *format, va_list args)
561 {
562 ✗ if (OMC_ACTIVE_WARNING_STREAM(stream)) {
563 char logBuffer[SIZE_LOG_BUFFER];
564 vsnprintf(logBuffer, SIZE_LOG_BUFFER, format, args);
565 ✗ messageFunction(OMC_LOG_TYPE_WARNING, stream, info, indentNext, logBuffer, 0, indexes);
566 }
567 ✗ }
568
569 ✗ void va_warningStreamPrint(int stream, int indentNext, const char *format, va_list args)
570 {
571 ✗ if (OMC_ACTIVE_WARNING_STREAM(stream)) {
572 char logBuffer[SIZE_LOG_BUFFER];
573 vsnprintf(logBuffer, SIZE_LOG_BUFFER, format, args);
574 ✗ messageFunction(OMC_LOG_TYPE_WARNING, stream, omc_dummyFileInfo, indentNext, logBuffer, 0, NULL);
575 }
576 ✗ }
577
578 3 void errorStreamPrint(int stream, int indentNext, const char *format, ...)
579 {
580 char logBuffer[SIZE_LOG_BUFFER];
581 va_list args;
582 3 va_start(args, format);
583 vsnprintf(logBuffer, SIZE_LOG_BUFFER, format, args);
584 3 va_end(args);
585 3 messageFunction(OMC_LOG_TYPE_ERROR, stream, omc_dummyFileInfo, indentNext, logBuffer, 0, NULL);
586 3 }
587
588 ✗ void va_errorStreamPrint(int stream, int indentNext, const char *format, va_list args)
589 {
590 char logBuffer[SIZE_LOG_BUFFER];
591 vsnprintf(logBuffer, SIZE_LOG_BUFFER, format, args);
592 ✗ messageFunction(OMC_LOG_TYPE_ERROR, stream, omc_dummyFileInfo, indentNext, logBuffer, 0, NULL);
593 ✗ }
594
595 ✗ void va_errorStreamPrintWithEquationIndexes(int stream, FILE_INFO info, int indentNext, const int *indexes, const char *format, va_list args)
596 {
597
598 char logBuffer[SIZE_LOG_BUFFER];
599 vsnprintf(logBuffer, SIZE_LOG_BUFFER, format, args);
600 ✗ messageFunction(OMC_LOG_TYPE_ERROR, stream, info, indentNext, logBuffer, 0, indexes);
601 ✗ }
602 #endif
603
604 #if !defined(OMC_MINIMAL_LOGGING)
605 /* A throw inside the nonlinear solver is a trial point it steps away from, so
606 * the message goes on OMC_LOG_NLS, as in omc_assert_simulation(). Not the
607 * integrator region: the failed-algebraic-solve throw is raised there. */
608 static inline int throwPrintsMessage(threadData_t *threadData)
609 {
610
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (!omc_useStream[OMC_LOG_ASSERT]) {
611 return 0;
612 }
613
4/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
57 if (threadData->currentErrorStage == ERROR_NONLINEARSOLVER) {
614 11 return OMC_ACTIVE_STREAM(OMC_LOG_NLS);
615 }
616 return 1;
617 }
618 #endif
619
620 #if defined(_MSC_VER)
621 static __declspec(thread) char lastSuppressedError[SIZE_LOG_BUFFER];
622 #else
623 static __thread char lastSuppressedError[SIZE_LOG_BUFFER];
624 #endif
625
626 15 void omc_note_suppressed_error(threadData_t *threadData, const char *format, va_list args)
627 {
628
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 if (threadData && threadData->currentErrorStage == ERROR_NONLINEARSOLVER) {
629 vsnprintf(lastSuppressedError, SIZE_LOG_BUFFER, format, args);
630 }
631 15 }
632
633 ✗ const char* omc_last_suppressed_error(void)
634 {
635 ✗ return lastSuppressedError;
636 }
637
638 3740 void omc_clear_last_suppressed_error(void)
639 {
640 3740 lastSuppressedError[0] = '\0';
641 3740 }
642
643 7 static inline jmp_buf* getBestJumpBuffer(threadData_t *threadData)
644 {
645
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (threadData->externalJumpBuffer) {
646 return threadData->externalJumpBuffer;
647 }
648 ✗ switch (threadData->currentErrorStage) {
649 ✗ case ERROR_EVENTSEARCH:
650 case ERROR_SIMULATION:
651 case ERROR_NONLINEARSOLVER:
652 case ERROR_INTEGRATOR:
653 case ERROR_OPTIMIZE:
654 #ifndef OMC_EMCC
655 ✗ if (threadData->simulationJumpBuffer) {
656 return threadData->simulationJumpBuffer;
657 }
658 ✗ fprintf(stderr, "getBestJumpBuffer got simulationJumpBuffer=%p\n", (void*)threadData->simulationJumpBuffer);
659 ✗ abort();
660 #endif
661 ✗ case ERROR_EVENTHANDLING:
662 default:
663 ✗ if (threadData->globalJumpBuffer) {
664 return threadData->globalJumpBuffer;
665 }
666 ✗ if (threadData->mmc_jumper) {
667 return threadData->mmc_jumper;
668 }
669 ✗ fprintf(stderr, "getBestJumpBuffer got mmc_jumper=%p, globalJumpBuffer=%p\n", (void*)threadData->mmc_jumper, (void*)threadData->globalJumpBuffer);
670 ✗ abort();
671 }
672 }
673
674 /* omc_thread_data() that reports the message being thrown, formatted only when
675 the lookup fails. */
676 61 threadData_t* omc_thread_data_va(threadData_t *threadData, const char *format, va_list args)
677 {
678
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 54 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
61 if (!threadData && !(threadData = (threadData_t*)pthread_getspecific(mmc_thread_data_key))) {
679 char msg[SIZE_LOG_BUFFER];
680 va_list copy;
681 ✗ va_copy(copy, args);
682 vsnprintf(msg, SIZE_LOG_BUFFER, format, copy);
683 ✗ va_end(copy);
684 ✗ threadData = omc_thread_data(NULL, msg);
685 }
686 61 return threadData;
687 }
688
689 /**
690 * @brief Variadic stream print and throw.
691 *
692 * Print message to OMC_LOG_ASSERT.
693 *
694 * @param threadData Thread data for throwing.
695 * @param format Format string.
696 * @param args Variadic argument list for format string
697 */
698 7 void va_throwStreamPrint(threadData_t *threadData, const char *format, va_list args)
699 {
700 7 threadData = omc_thread_data_va(threadData, format, args);
701 #if !defined(OMC_MINIMAL_LOGGING)
702 ✗ if (throwPrintsMessage(threadData)) {
703 char logBuffer[SIZE_LOG_BUFFER];
704 vsnprintf(logBuffer, SIZE_LOG_BUFFER, format, args);
705 3 messageFunction(OMC_LOG_TYPE_DEBUG, OMC_LOG_ASSERT, omc_dummyFileInfo, 0, logBuffer, 0, NULL);
706 } else {
707 4 omc_note_suppressed_error(threadData, format, args);
708 }
709 #endif
710 7 longjmp(*getBestJumpBuffer(threadData), 1);
711 }
712
713 /**
714 * @brief Print message to OMC_LOG_ASSERT and throw.
715 *
716 * @param threadData Thread data for throwing.
717 * @param format Format string.
718 * @param ... Additional arguments for format string.
719 */
720 4 void throwStreamPrint(threadData_t *threadData, const char *format, ...)
721 {
722 #if !defined(OMC_MINIMAL_LOGGING)
723 va_list args;
724 4 va_start(args, format);
725 4 va_throwStreamPrint(threadData, format, args);
726 va_end(args);
727 #else
728 threadData = omc_thread_data(threadData, format);
729 longjmp(*getBestJumpBuffer(threadData), 1);
730 #endif
731 }
732
733 #if !defined(OMC_METAMODELICA_RUNTIME)
734 /* A raise lands at the nearest checker, which retries the step. During event
735 handling there is nothing left to retry from, so jump to the stage's landing. */
736 7 void omc_external_error(threadData_t *threadData)
737 {
738
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (threadData->currentErrorStage == ERROR_EVENTHANDLING) {
739 ✗ longjmp(*getBestJumpBuffer(threadData), 1);
740 }
741 7 OMC_ERROR_RAISE();
742 7 }
743 #endif
744
745 2251 void omc_error_raise(threadData_t *threadData)
746 {
747 2251 threadData->errorState = 1;
748 2251 }
749
750 203729052 int omc_error_take(threadData_t *threadData)
751 {
752 203729052 int raised = threadData->errorState;
753 203729052 threadData->errorState = 0;
754 203729052 return raised;
755 }
756
757 ✗ jmp_buf *omc_external_jump_buffer(threadData_t *threadData)
758 {
759 ✗ return threadData->externalJumpBuffer;
760 }
761
762 /* The raising counterparts of throwStreamPrint*, for generated code: they
763 return, so the caller leaves through its own _return: and runs its releases. */
764 14 void raiseStreamPrint(threadData_t *threadData, const char *format, ...)
765 {
766 va_list args;
767 14 va_start(args, format);
768 14 threadData = omc_thread_data_va(threadData, format, args);
769
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 va_end(args);
770 #if !defined(OMC_MINIMAL_LOGGING)
771
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (throwPrintsMessage(threadData)) {
772 char logBuffer[SIZE_LOG_BUFFER];
773 3 va_start(args, format);
774 vsnprintf(logBuffer, SIZE_LOG_BUFFER, format, args);
775 3 va_end(args);
776 3 messageFunction(OMC_LOG_TYPE_DEBUG, OMC_LOG_ASSERT, omc_dummyFileInfo, 0, logBuffer, 0, NULL);
777 } else {
778 11 va_start(args, format);
779 11 omc_note_suppressed_error(threadData, format, args);
780 11 va_end(args);
781 }
782 #endif
783 14 OMC_ERROR_RAISE();
784 14 }
785
786 40 void raiseStreamPrintWithEquationIndexes(threadData_t *threadData, FILE_INFO info, const int *indexes, const char *format, ...)
787 {
788 va_list args;
789 40 va_start(args, format);
790 40 threadData = omc_thread_data_va(threadData, format, args);
791
1/2
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
40 va_end(args);
792 #if !defined(OMC_MINIMAL_LOGGING)
793 ✗ if (throwPrintsMessage(threadData)) {
794 char logBuffer[SIZE_LOG_BUFFER];
795 40 va_start(args, format);
796 vsnprintf(logBuffer, SIZE_LOG_BUFFER, format, args);
797 40 va_end(args);
798 40 messageFunction(OMC_LOG_TYPE_DEBUG, OMC_LOG_ASSERT, info, 0, logBuffer, 0, indexes);
799 } else {
800 ✗ va_start(args, format);
801 ✗ omc_note_suppressed_error(threadData, format, args);
802 ✗ va_end(args);
803 }
804 #endif
805 40 OMC_ERROR_RAISE();
806 40 }
807
808 /**
809 * @brief Print message with equation indices to OMC_LOG_ASSERT stream and throw.
810 *
811 * @param threadData Thread data for throwing.
812 * @param info File info, can be omc_dummyFileInfo.
813 * @param indexes Equation indices.
814 * @param format Format string.
815 * @param ... Additional arguments for format string.
816 */
817 ✗ void throwStreamPrintWithEquationIndexes(threadData_t *threadData, FILE_INFO info, const int *indexes, const char *format, ...)
818 {
819 va_list args;
820 ✗ va_start(args, format);
821 ✗ threadData = omc_thread_data_va(threadData, format, args);
822 ✗ va_end(args);
823 #if !defined(OMC_MINIMAL_LOGGING)
824 ✗ if (throwPrintsMessage(threadData)) {
825 char logBuffer[SIZE_LOG_BUFFER];
826 ✗ va_start(args, format);
827 vsnprintf(logBuffer, SIZE_LOG_BUFFER, format, args);
828 ✗ va_end(args);
829 ✗ messageFunction(OMC_LOG_TYPE_DEBUG, OMC_LOG_ASSERT, info, 0, logBuffer, 0, indexes);
830 } else {
831 ✗ va_start(args, format);
832 ✗ omc_note_suppressed_error(threadData, format, args);
833 ✗ va_end(args);
834 }
835 #endif
836 ✗ longjmp(*getBestJumpBuffer(threadData), 1);
837 }
838