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