+2014-08-19 Carl Hetherington <cth@carlh.net>
+
+ * Attempt to fix random crashes on OS X (especially during encodes)
+ thought to be caused by multiple threads using (different) stringstreams
+ at the same time; see src/lib/safe_stringstream.h
+
2014-08-09 Carl Hetherington <cth@carlh.net>
* Version 1.72.10 released.
for (int j = 0; j < b->channels(); ++j) {
float s = b->data(j)[i];
if (fabsf (s) < 10e-7) {
- /* stringstream can't serialise and recover inf or -inf, so prevent such
+ /* SafeStringStream can't serialise and recover inf or -inf, so prevent such
values by replacing with this (140dB down) */
s = 10e-7;
}
#ifndef STRING_COMPOSE_H
#define STRING_COMPOSE_H
-#include <sstream>
#include <string>
#include <list>
#include <map> // for multimap
+#include "safe_stringstream.h"
namespace StringPrivate
{
std::string str() const;
private:
- std::ostringstream os;
+ SafeStringStream os;
int arg_no;
// we store the output as a list - when the output string is requested, the
*/
-#include <sstream>
#include <cstdlib>
#include <fstream>
#include <glib.h>
#include "ui_signaller.h"
#include "exceptions.h"
#include "film.h"
+#include "safe_stringstream.h"
#include "i18n.h"
using std::string;
-using std::stringstream;
using std::set;
using std::list;
using std::cout;
string
Content::identifier () const
{
- stringstream s;
+ SafeStringStream s;
s << Content::digest()
<< "_" << position()
#include <stdexcept>
#include <cstdio>
#include <iomanip>
-#include <sstream>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include "i18n.h"
using std::string;
-using std::stringstream;
using std::cout;
using boost::shared_ptr;
using libdcp::Size;
LOG_GENERAL (N_("Sending frame %1 to remote"), _index);
/* Send XML metadata */
- stringstream xml;
- doc.write_to_stream (xml, "UTF-8");
- socket->write (xml.str().length() + 1);
- socket->write ((uint8_t *) xml.str().c_str(), xml.str().length() + 1);
+ string xml = doc.write_to_string ("UTF-8");
+ socket->write (xml.length() + 1);
+ socket->write ((uint8_t *) xml.c_str(), xml.length() + 1);
/* Send binary data */
_frame->send_binary (socket);
#include "log.h"
#include "exceptions.h"
#include "frame_rate_change.h"
+#include "safe_stringstream.h"
#include "i18n.h"
#define LOG_GENERAL(...) film->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL);
using std::string;
-using std::stringstream;
using std::vector;
using std::list;
using std::cout;
return "";
}
- stringstream s;
+ SafeStringStream s;
s << String::compose (_("%1 frames; %2 frames per second"), video_length_after_3d_combine(), video_frame_rate()) << "\n";
s << VideoContent::information ();
string
FFmpegContent::identifier () const
{
- stringstream s;
+ SafeStringStream s;
s << VideoContent::identifier();
#include <stdexcept>
#include <vector>
-#include <sstream>
#include <iomanip>
#include <iostream>
#include <stdint.h>
}
#include "ffmpeg_examiner.h"
#include "ffmpeg_content.h"
+#include "safe_stringstream.h"
#include "i18n.h"
using std::string;
using std::cout;
using std::max;
-using std::stringstream;
using boost::shared_ptr;
using boost::optional;
string
FFmpegExaminer::audio_stream_name (AVStream* s) const
{
- stringstream n;
+ SafeStringStream n;
n << stream_name (s);
string
FFmpegExaminer::subtitle_stream_name (AVStream* s) const
{
- stringstream n;
+ SafeStringStream n;
n << stream_name (s);
string
FFmpegExaminer::stream_name (AVStream* s) const
{
- stringstream n;
+ SafeStringStream n;
if (s->metadata) {
AVDictionaryEntry const * lang = av_dict_get (s->metadata, "language", 0, 0);
#include <algorithm>
#include <fstream>
#include <cstdlib>
-#include <sstream>
#include <iomanip>
#include <unistd.h>
#include <boost/filesystem.hpp>
#include "ratio.h"
#include "cross.h"
#include "cinema.h"
+#include "safe_stringstream.h"
#include "i18n.h"
using std::string;
-using std::stringstream;
using std::multimap;
using std::pair;
using std::map;
{
assert (container ());
- stringstream s;
+ SafeStringStream s;
s.imbue (std::locale::classic ());
s << container()->id()
string
Film::isdcf_name (bool if_created_now) const
{
- stringstream d;
+ SafeStringStream d;
string raw_name = name ();
boost::filesystem::path p;
p /= info_dir ();
- stringstream s;
+ SafeStringStream s;
s.width (8);
s << setfill('0') << f;
p /= "j2c";
p /= video_identifier ();
- stringstream s;
+ SafeStringStream s;
s.width (8);
s << setfill('0') << f;
#include "exceptions.h"
#include "image.h"
#include "ffmpeg_content.h"
+#include "safe_stringstream.h"
#include "i18n.h"
-using std::stringstream;
using std::string;
using std::list;
using std::pair;
throw DecodeError (N_("Could not create buffer sink filter"));
}
- stringstream a;
+ SafeStringStream a;
a << "video_size=" << _size.width << "x" << _size.height << ":"
<< "pix_fmt=" << _pixel_format << ":"
<< "time_base=1/1:"
#include "film.h"
#include "job.h"
#include "frame_rate_change.h"
+#include "safe_stringstream.h"
#include "i18n.h"
using std::string;
using std::cout;
-using std::stringstream;
using boost::shared_ptr;
ImageContent::ImageContent (shared_ptr<const Film> f, boost::filesystem::path p)
string
ImageContent::identifier () const
{
- stringstream s;
+ SafeStringStream s;
s << VideoContent::identifier ();
s << "_" << video_length();
return s.str ();
#include <curl/curl.h>
#include <zip.h>
#include "util.h"
+#include "safe_stringstream.h"
#include "i18n.h"
using std::string;
-using std::stringstream;
using std::list;
using boost::optional;
using boost::function;
return list<string> ();
}
- stringstream s (ls_raw);
- string line;
+ SafeStringStream s (ls_raw);
list<string> ls;
while (s.good ()) {
- getline (s, line);
+ string const line = s.getline ();
if (line.length() > 55) {
string const file = line.substr (55);
if (file != "." && file != "..") {
#include "cross.h"
#include "ui_signaller.h"
#include "exceptions.h"
+#include "safe_stringstream.h"
#include "i18n.h"
using std::string;
using std::list;
using std::cout;
-using std::stringstream;
using boost::shared_ptr;
Job::Job (shared_ptr<const Film> f)
pc = 99;
}
- stringstream s;
+ SafeStringStream s;
if (!finished ()) {
s << pc << N_("%");
if (p >= 0 && t > 10 && r > 0) {
#include "util.h"
#include "film.h"
#include "config.h"
+#include "safe_stringstream.h"
using std::list;
using std::string;
-using std::stringstream;
using std::cout;
using boost::shared_ptr;
quickmail_initialize ();
- stringstream start;
+ SafeStringStream start;
start << from.date() << " " << from.time_of_day();
- stringstream end;
+ SafeStringStream end;
end << to.date() << " " << to.time_of_day();
string subject = Config::instance()->kdm_subject();
boost::algorithm::replace_all (body, "$END_TIME", end.str ());
boost::algorithm::replace_all (body, "$CINEMA_NAME", i->cinema->name);
- stringstream screens;
+ SafeStringStream screens;
for (list<ScreenKDM>::const_iterator j = i->screen_kdms.begin(); j != i->screen_kdms.end(); ++j) {
screens << j->screen->name << ", ";
}
#include "log.h"
#include "cross.h"
#include "config.h"
+#include "safe_stringstream.h"
#include "i18n.h"
time (&t);
string a = ctime (&t);
- stringstream s;
+ SafeStringStream s;
s << a.substr (0, a.length() - 1) << N_(": ");
if (type & TYPE_ERROR) {
struct timeval tv;
gettimeofday (&tv, 0);
- stringstream s;
+ SafeStringStream s;
s << tv.tv_sec << N_(":") << tv.tv_usec << N_(" ") << m;
do_log (s.str ());
}
*/
#include <iomanip>
-#include <sstream>
#include <openssl/md5.h>
#include "md5_digester.h"
+#include "safe_stringstream.h"
using std::string;
-using std::stringstream;
using std::hex;
using std::setfill;
using std::setw;
unsigned char digest[MD5_DIGEST_LENGTH];
MD5_Final (digest, &_context);
- stringstream s;
+ SafeStringStream s;
for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
s << hex << setfill('0') << setw(2) << ((int) digest[i]);
}
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <boost/thread/mutex.hpp>
+#include "safe_stringstream.h"
+
+boost::mutex SafeStringStream::_mutex;
--- /dev/null
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef DCPOMATIC_SAFE_STRINGSTREAM_H
+#define DCPOMATIC_SAFE_STRINGSTREAM_H
+
+#include <boost/thread/mutex.hpp>
+
+/* I've not been able to reproduce it, but there have been reports that DCP-o-matic crashes
+ * on OS X with two simultaneous backtraces that look like this:
+ *
+ * 0 libSystem.B.dylib 0x00007fff84ebe264 __numeric_load_locale + 125
+ * 1 libSystem.B.dylib 0x00007fff84e2aac4 loadlocale + 323
+ * 2 libstdc++.6.dylib 0x00007fff8976ba69 std::__convert_from_v(int* const&, char*, int, char const*, ...) + 199
+ * 3 libstdc++.6.dylib 0x00007fff8974e99b std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char,
+std::char_traits<char> > >::_M_insert_float<double>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, char, double) const + 199
+ * 4 libstdc++.6.dylib 0x00007fff8974ebc0 std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> >
+>::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, double) const + 28
+ * 5 libstdc++.6.dylib 0x00007fff897566a2 std::ostream& std::ostream::_M_insert<double>(double) + 178
+ * 6 libdcpomatic.dylib 0x0000000100331e21 StringPrivate::Composition& StringPrivate::Composition::arg<float>(float const&) + 33
+ *
+ * in two different threads. I'm assuming that for some bizarre reason it is unsafe to use two separate stringstream
+ * objects in different threads on OS X. This is a hack to work around it.
+ */
+
+class SafeStringStream
+{
+public:
+ SafeStringStream ()
+ {}
+
+ SafeStringStream (std::string s)
+ : _stream (s)
+ {}
+
+ template <class T>
+ std::ostream& operator<< (T val)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _stream << val;
+ return _stream;
+ }
+
+ template <class T>
+ std::istream& operator>> (T& val)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _stream >> val;
+ return _stream;
+ }
+
+ std::string str () const {
+ return _stream.str ();
+ }
+
+ void str (std::string const & s) {
+ _stream.str (s);
+ }
+
+ void imbue (std::locale const & loc)
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _stream.imbue (loc);
+ }
+
+ void width (int w)
+ {
+ _stream.width (w);
+ }
+
+ void precision (int p)
+ {
+ _stream.precision (p);
+ }
+
+ bool good () const
+ {
+ return _stream.good ();
+ }
+
+ std::string getline ()
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ std::string s;
+ std::getline (_stream, s);
+ return s;
+ }
+
+ void setf (std::ios_base::fmtflags flags, std::ios_base::fmtflags mask)
+ {
+ _stream.setf (flags, mask);
+ }
+
+private:
+ static boost::mutex _mutex;
+ std::stringstream _stream;
+};
+
+#endif
#include <string>
#include <vector>
-#include <sstream>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <boost/scoped_array.hpp>
#include "config.h"
#include "cross.h"
#include "player_video_frame.h"
+#include "safe_stringstream.h"
#include "i18n.h"
#define LOG_ERROR_NC(...) _log->log (__VA_ARGS__, Log::TYPE_ERROR);
using std::string;
-using std::stringstream;
using std::multimap;
using std::vector;
using std::list;
scoped_array<char> buffer (new char[length]);
socket->read (reinterpret_cast<uint8_t*> (buffer.get()), length);
- stringstream s (buffer.get());
+ string s (buffer.get());
shared_ptr<cxml::Document> xml (new cxml::Document ("EncodingRequest"));
- xml->read_stream (s);
+ xml->read_string (s);
if (xml->number_child<int> ("Version") != SERVER_LINK_VERSION) {
cerr << "Mismatched server/client versions\n";
LOG_ERROR_NC ("Mismatched server/client versions");
struct timeval end;
gettimeofday (&end, 0);
- stringstream message;
+ SafeStringStream message;
message.precision (2);
message << fixed
<< "Encoded frame " << frame << " from " << ip << ": "
xmlpp::Document doc;
xmlpp::Element* root = doc.create_root_node ("ServerAvailable");
root->add_child("Threads")->add_child_text (raw_convert<string> (_worker_threads.size ()));
- stringstream xml;
- doc.write_to_stream (xml, "UTF-8");
+ string xml = doc.write_to_string ("UTF-8");
shared_ptr<Socket> socket (new Socket);
try {
socket->connect (boost::asio::ip::tcp::endpoint (_broadcast.send_endpoint.address(), Config::instance()->server_port_base() + 1));
- socket->write (xml.str().length() + 1);
- socket->write ((uint8_t *) xml.str().c_str(), xml.str().length() + 1);
+ socket->write (xml.length() + 1);
+ socket->write ((uint8_t *) xml.c_str(), xml.length() + 1);
} catch (...) {
}
#include "ui_signaller.h"
using std::string;
-using std::stringstream;
using std::list;
using std::vector;
using std::cout;
scoped_array<char> buffer (new char[length]);
sock->read (reinterpret_cast<uint8_t*> (buffer.get()), length);
- stringstream s (buffer.get());
+ string s (buffer.get());
shared_ptr<cxml::Document> xml (new cxml::Document ("ServerAvailable"));
- xml->read_stream (s);
+ xml->read_string (s);
string const ip = sock->socket().remote_endpoint().address().to_string ();
if (!server_found (ip)) {
#include "compose.hpp"
#include "job.h"
#include "util.h"
+#include "safe_stringstream.h"
#include "i18n.h"
using std::string;
-using std::stringstream;
using std::cout;
using boost::shared_ptr;
using libdcp::raw_convert;
return "";
}
- stringstream s;
+ SafeStringStream s;
s << String::compose (
_("%1 channels, %2kHz, %3 samples"),
#include <iomanip>
#include <ostream>
#include <stdexcept>
-#include <sstream>
#include "stack.hpp"
#include "film.h"
#include "transcoder.h"
#include "log.h"
+#include "safe_stringstream.h"
#include "i18n.h"
#define LOG_ERROR_NC(...) _film->log()->log (__VA_ARGS__, Log::TYPE_ERROR);
using std::string;
-using std::stringstream;
using std::fixed;
using std::setprecision;
using boost::shared_ptr;
return Job::status ();
}
- stringstream s;
+ SafeStringStream s;
s << Job::status ();
*/
#include <string>
-#include <sstream>
#include <boost/algorithm/string.hpp>
#include <curl/curl.h>
#include <libcxml/cxml.h>
#include "update.h"
#include "version.h"
#include "ui_signaller.h"
+#include "safe_stringstream.h"
#define BUFFER_SIZE 1024
using std::cout;
using std::min;
using std::string;
-using std::stringstream;
using libdcp::raw_convert;
UpdateChecker* UpdateChecker::_instance = 0;
}
_buffer[_offset] = '\0';
- stringstream s;
- s << _buffer;
+ string s (_buffer);
cxml::Document doc ("Update");
- doc.read_stream (s);
+ doc.read_string (s);
{
boost::mutex::scoped_lock lm (_data_mutex);
* @brief Some utility functions and classes.
*/
-#include <sstream>
#include <iomanip>
#include <iostream>
#include <fstream>
#include "cross.h"
#include "video_content.h"
#include "md5_digester.h"
+#include "safe_stringstream.h"
#ifdef DCPOMATIC_WINDOWS
#include "stack.hpp"
#endif
#include "i18n.h"
using std::string;
-using std::stringstream;
using std::setfill;
using std::ostream;
using std::endl;
int h = m / 60;
m -= (h * 60);
- stringstream hms;
+ SafeStringStream hms;
hms << h << N_(":");
hms.width (2);
hms << std::setfill ('0') << m << N_(":");
int h = m / 60;
m -= (h * 60);
- stringstream ap;
+ SafeStringStream ap;
bool const hours = h > 0;
bool const minutes = h < 10 && m > 0;
static string
ffmpeg_version_to_string (int v)
{
- stringstream s;
+ SafeStringStream s;
s << ((v & 0xff0000) >> 16) << N_(".") << ((v & 0xff00) >> 8) << N_(".") << (v & 0xff);
return s.str ();
}
string
dependency_version_summary ()
{
- stringstream s;
+ SafeStringStream s;
s << N_("libopenjpeg ") << opj_version () << N_(", ")
<< N_("libavcodec ") << ffmpeg_version_to_string (avcodec_version()) << N_(", ")
<< N_("libavfilter ") << ffmpeg_version_to_string (avfilter_version()) << N_(", ")
#include "film.h"
#include "exceptions.h"
#include "frame_rate_change.h"
+#include "safe_stringstream.h"
#include "i18n.h"
int const VideoContentProperty::COLOUR_CONVERSION = 5;
using std::string;
-using std::stringstream;
using std::setprecision;
using std::cout;
using std::vector;
return "";
}
- stringstream s;
+ SafeStringStream s;
s << String::compose (
_("%1x%2 pixels (%3:1)"),
string
VideoContent::identifier () const
{
- stringstream s;
+ SafeStringStream s;
s << Content::identifier()
<< "_" << crop().left
<< "_" << crop().right
string
VideoContentScale::id () const
{
- stringstream s;
+ SafeStringStream s;
if (_ratio) {
s << _ratio->id () << "_";
playlist.cc
ratio.cc
resampler.cc
+ safe_stringstream.cc
scp_dcp_job.cc
scaler.cc
send_kdm_email_job.cc
using std::cout;
using std::string;
using std::wstring;
-using std::stringstream;
using std::map;
using std::make_pair;
using std::list;
#include "lib/kdm.h"
#include "lib/config.h"
#include "lib/exceptions.h"
+#include "lib/safe_stringstream.h"
using std::string;
-using std::stringstream;
using std::cout;
using std::cerr;
using std::list;
static boost::posix_time::time_duration
duration_from_string (string d)
{
- stringstream s (d);
+ SafeStringStream s (d);
int N;
string unit;
s >> N >> unit;
#include "lib/server.h"
#include <iostream>
#include <stdexcept>
-#include <sstream>
#include <cstring>
#include <vector>
#include <unistd.h>
#include <wx/spinctrl.h>
#include <wx/gbsizer.h>
#include "lib/colour_conversion.h"
+#include "lib/safe_stringstream.h"
#include "wx_util.h"
#include "colour_conversion_editor.h"
using std::string;
using std::cout;
-using std::stringstream;
using boost::shared_ptr;
using boost::lexical_cast;
_input_gamma_linearised->SetValue (conversion.input_gamma_linearised);
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
- stringstream s;
+ SafeStringStream s;
s.setf (std::ios::fixed, std::ios::floatfield);
s.precision (7);
s << conversion.matrix (i, j);
#include "lib/playlist.h"
#include "lib/content.h"
#include "lib/content_factory.h"
+#include "lib/safe_stringstream.h"
#include "timecode.h"
#include "wx_util.h"
#include "film_editor.h"
using std::string;
using std::cout;
-using std::stringstream;
using std::pair;
using std::fixed;
using std::setprecision;
return;
}
- stringstream s;
+ SafeStringStream s;
for (list<FilmEditorPanel*>::iterator i = _panels.begin(); i != _panels.end(); ++i) {
(*i)->film_changed (p);
*/
-#include <sstream>
#include "lib/film.h"
#include "lib/exceptions.h"
#include "job_wrapper.h"
#include <boost/bind.hpp>
#include "lib/film.h"
#include "lib/config.h"
+#include "lib/safe_stringstream.h"
#include "properties_dialog.h"
#include "wx_util.h"
using std::string;
-using std::stringstream;
using std::fixed;
using std::setprecision;
using boost::shared_ptr;
_frames->SetLabel (std_to_wx (lexical_cast<string> (_film->time_to_video_frames (_film->length()))));
double const disk = double (_film->required_disk_space()) / 1073741824.0f;
- stringstream s;
+ SafeStringStream s;
s << fixed << setprecision (1) << disk << wx_to_std (_("Gb"));
_disk->SetLabel (std_to_wx (s.str ()));
string
PropertiesDialog::frames_already_encoded () const
{
- stringstream u;
+ SafeStringStream u;
try {
u << _film->encoded_frames ();
} catch (boost::thread_interrupted &) {
*/
-#include <sstream>
#include <boost/test/unit_test.hpp>
#include <boost/filesystem.hpp>
#include <boost/date_time.hpp>