casadi_logger.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 #include "casadi_common.hpp"
26 #include "casadi_logger.hpp"
27 
28 #ifdef CASADI_WITH_THREAD
29 #ifdef CASADI_WITH_THREAD_MINGW
30 #include <mingw.mutex.h>
31 #else // CASADI_WITH_THREAD_MINGW
32 #include <mutex>
33 #endif // CASADI_WITH_THREAD_MINGW
34 #endif //CASADI_WITH_THREAD
35 
36 namespace casadi {
37 
38 #ifdef CASADI_WITH_THREAD
39  std::mutex mutex_logger;
40 #endif //CASADI_WITH_THREAD
41 
42  void Logger::WriteFunThreadSafe(const char* s, std::streamsize num, bool error) {
43 #ifdef CASADI_WITH_THREAD
44  std::lock_guard<std::mutex> lock(mutex_logger);
45 #endif //CASADI_WITH_THREAD
46  writeFun(s, num, error);
47  }
48 
49  void Logger::FlushThreadSafe(bool error) {
50 #ifdef CASADI_WITH_THREAD
51  std::lock_guard<std::mutex> lock(mutex_logger);
52 #endif //CASADI_WITH_THREAD
53  flush(error);
54  }
55 
56  void (*Logger::writeFun)(const char* s, std::streamsize num, bool error) =
58 
59  void (*Logger::flush)(bool error) =Logger::flushDefault;
60 
61  std::ostream& uout() {
62  // Thread-local stream: each thread gets its own instance
63  // This prevents data races on stream state (width, fill, flags, etc.)
64  // while WriteFunThreadSafe still protects actual I/O with mutex
65  // ThreadLocalStorage avoids MinGW thread_local destructor ordering bug
66  static thread_local ThreadLocalStorage<Logger::Stream<false>> instance;
67  return instance.get();
68  }
69 
70  std::ostream& uerr() {
71  // Thread-local stream: each thread gets its own instance
72  // ThreadLocalStorage avoids MinGW thread_local destructor ordering bug
73  static thread_local ThreadLocalStorage<Logger::Stream<true>> instance;
74  return instance.get();
75  }
76 
77 } // namespace casadi
78 
79 extern "C" {
80  int casadi_printf(const char *fmt, ...) {
81  // Variable number of arguments
82  va_list args;
83  va_start(args, fmt);
84  // Static & dynamic buffers
85  char buf[256];
86  size_t buf_sz = sizeof(buf);
87  char* buf_dyn = nullptr;
88  // Try to print with a small buffer
89  casadi_int n = vsnprintf(buf, buf_sz, fmt, args);
90  // Need a larger buffer?
91  if (n>static_cast<casadi_int>(buf_sz)) {
92  buf_sz = static_cast<size_t>(n+1);
93  buf_dyn = new char[buf_sz];
94  n = vsnprintf(buf_dyn, buf_sz, fmt, args);
95  }
96  // Print buffer content
97  if (n>=0) casadi::uout() << (buf_dyn ? buf_dyn : buf) << std::flush;
98  // Cleanup
99  delete[] buf_dyn;
100  va_end(args);
101  return n;
102  }
103 }
static void(* writeFun)(const char *s, std::streamsize num, bool error)
Print warnings, can be redefined.
static void FlushThreadSafe(bool error)
static void flushDefault(bool error)
By default, flush std::cout or std::cerr.
static void writeDefault(const char *s, std::streamsize num, bool error)
By default, print to std::cout or std::cerr.
static void WriteFunThreadSafe(const char *s, std::streamsize num, bool error)
static void(* flush)(bool error)
Flush buffers.
Thread-local storage wrapper that avoids destructor calls.
The casadi namespace.
Definition: archiver.cpp:28
std::ostream & uerr()
std::ostream & uout()