1 /*
2 * mp3plot - Bitrate analysis tool
3 *
4 * Copyright (C) 2007, 2009 Toni Corvera
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 // $Id: spinner.cc 1215 2009-04-25 12:47:38Z $
22
23 #include "spinner.h"
24
25 #include <iostream>
26 #include <cassert>
27 #include <cstring> // strlen
28 #include <cstdlib> // exit
29
30 // FIXME!!!: I've *once so far* found a threadlock while running the
31 // new, Boost.Thread-based, code. Should look into it
32
33 #define SYMS_DEF "|/-\\"
34
35 #include <boost/version.hpp> // The use of boost conditions changed at some point...
36 #include <boost/ref.hpp>
37 #include <boost/thread.hpp>
38
39 #if BOOST_VERSION < 103401
40 // Conditions were introduced in 1.34.1, lower versions aren't supported
41 # error At least boost 1.34.1 is required
42 #elif BOOST_VERSION < 103500
43 // the locking code changed in 1.35.0. Lower versions code:
44 typedef boost::condition condition_type;
45 typedef boost::mutex::scoped_lock lock_type;
46 #else
47 typedef boost::condition_variable condition_type;
48 typedef boost::unique_lock<boost::mutex> lock_type;
49 #endif
50
51 using namespace std;
52
53 namespace {
54 const size_t LEN=::strlen(SYMS_DEF);
55 const char * SYMS_ = SYMS_DEF;
56
57 condition_type cond;
58 boost::mutex lmutex; // not really used, but condition requires it
59
60 /**
61 * \brief Functor with the actual spinner code
62 */
63 struct impl {
operator ()__anon16a43d300111::impl64 void operator()() {
65 must_stop = false;
66 idx = 0;
67
68 while (!must_stop) {
69 lock_type lock(lmutex);
70 cond.wait(lock); // wait until notify_*
71 cerr << "\r[" << SYMS_[static_cast<int>(idx)] << "]";
72 idx = ( idx + 1 ) % LEN;
73
74 if(must_stop) break;
75 }
76 // Cleanup output
77 cerr << flush << "\r" << flush;
78 }
79 volatile bool must_stop;
80 int idx;
81 };
82 }
83
84 namespace net_outlyer {
85
86 const char * spinner::SYMS = SYMS_DEF;
87
88 impl the_impl;
89
start()90 void spinner::start() {
91 lock_type lock(lmutex);
92 // Note the red is VITAL, boost::thread takes makes a private copy of the
93 // object. Due to the way the program is written that duplicated the
94 // mutex/condition code leading to assertion failures when deallocating
95 // them
96 // <http://www.boost.org/doc/libs/1_38_0/doc/html/thread/thread_management.html>
97 boost::thread t(boost::ref(the_impl));
98 // On exit from start(), t will become a detached thread
99 }
100
101 // This is called from the parent thread, it writes a byte on the shared pipe
102 // deprecated
step()103 void spinner::step() {
104 (*this)++;
105 }
106
107 // Can't define with a return type, it stopped working
108
operator ++(int)109 void spinner::operator++(int) {
110 cond.notify_one();
111 }
112
operator ++()113 void spinner::operator++() {
114 cond.notify_one();
115 }
116
117 // This is called from the parent thread, instructs the child thread to stop spinning
118 // For some reason the end of the loop isn't reached (see impl's details)
stop()119 void spinner::stop() {
120 the_impl.must_stop = true;
121 cond.notify_one(); // Otherwise won't exit the loop
122 }
123
~spinner()124 spinner::~spinner() {
125 stop();
126 }
127
128
129 } // namespace net_outlyer
130
131 // vim:set ts=4 et ai:
132