Logging improvements to allow prettier displays in the server GUI.
[dcpomatic.git] / src / lib / safe_stringstream.h
1 /*
2     Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifndef DCPOMATIC_SAFE_STRINGSTREAM_H
21 #define DCPOMATIC_SAFE_STRINGSTREAM_H
22
23 #include <boost/thread/mutex.hpp>
24
25 /* I've not been able to reproduce it, but there have been reports that DCP-o-matic crashes
26  * on OS X with two simultaneous backtraces that look like this:
27  *
28  * 0 libSystem.B.dylib  0x00007fff84ebe264 __numeric_load_locale + 125
29  * 1 libSystem.B.dylib  0x00007fff84e2aac4 loadlocale + 323
30  * 2 libstdc++.6.dylib  0x00007fff8976ba69 std::__convert_from_v(int* const&, char*, int, char const*, ...) + 199
31  * 3 libstdc++.6.dylib  0x00007fff8974e99b std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char,
32 std::char_traits<char> > >::_M_insert_float<double>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, char, double) const + 199
33  * 4 libstdc++.6.dylib  0x00007fff8974ebc0 std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> >
34 >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, double) const + 28
35  * 5 libstdc++.6.dylib  0x00007fff897566a2 std::ostream& std::ostream::_M_insert<double>(double) + 178
36  * 6 libdcpomatic.dylib 0x0000000100331e21 StringPrivate::Composition& StringPrivate::Composition::arg<float>(float const&) + 33
37  *
38  * in two different threads.  I'm assuming that for some bizarre reason it is unsafe to use two separate stringstream
39  * objects in different threads on OS X.  This is a hack to work around it.
40  */
41
42 class SafeStringStream
43 {
44 public:
45         SafeStringStream ()
46         {}
47
48         SafeStringStream (std::string s)
49                 : _stream (s)
50         {}
51
52         template <class T>
53         std::ostream& operator<< (T val)
54         {
55                 boost::mutex::scoped_lock lm (_mutex);
56                 _stream << val;
57                 return _stream;
58         }
59
60         template <class T>
61         std::istream& operator>> (T& val)
62         {
63                 boost::mutex::scoped_lock lm (_mutex);
64                 _stream >> val;
65                 return _stream;
66         }
67
68         std::string str () const {
69                 return _stream.str ();
70         }
71
72         void str (std::string const & s) {
73                 _stream.str (s);
74         }
75
76         void imbue (std::locale const & loc)
77         {
78                 boost::mutex::scoped_lock lm (_mutex);
79                 _stream.imbue (loc);
80         }
81
82         void width (int w)
83         {
84                 _stream.width (w);
85         }
86
87         void fill (int f)
88         {
89                 _stream.fill (f);
90         }
91
92         void precision (int p)
93         {
94                 _stream.precision (p);
95         }
96
97         bool good () const
98         {
99                 return _stream.good ();
100         }
101
102         std::string getline ()
103         {
104                 boost::mutex::scoped_lock lm (_mutex);
105                 std::string s;
106                 std::getline (_stream, s);
107                 return s;
108         }
109
110         void setf (std::ios_base::fmtflags flags, std::ios_base::fmtflags mask)
111         {
112                 _stream.setf (flags, mask);
113         }
114
115 private:
116         static boost::mutex _mutex;
117         std::stringstream _stream;
118 };
119
120 #endif