/[svn]/linuxsampler/trunk/src/shell/KeyboardReader.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/shell/KeyboardReader.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3766 - (hide annotations) (download)
Mon Apr 6 12:41:49 2020 UTC (4 years, 1 month ago) by schoenebeck
File size: 3438 byte(s)
Fixed deadlocks (e.g. when restarting engines).

* Individual thread implementations (e.g. disk thread, etc.):
  Disable thread cancellation on critical sections, e.g. when holding
  mutex locks, to prevent deadlocks if thread is stopped and/or
  restarted.

* Added TestCancel() calls to thread implementations if missing.

* No need to wrap Thread::TestCancel() calls into
  CONFIG_PTHREAD_TESTCANCEL macro conditions (since TestCancel() is
  already a stub on systems which don't have pthread_testcancel()
  available).

* If compiled for debugging: give each thread a human readable name
  to simplify debugging of multi-threading issues.

* DiskThreadBase: TestCancel() and pthread_testcancel() calls are
  per-se redundant, so only call TestCancel().

* Added missing override keywords to silent compiler warnings.

* Bumped version (2.1.1.svn54).

1 schoenebeck 2515 /*
2     * LSCP Shell
3     *
4 schoenebeck 3766 * Copyright (c) 2014 - 2020 Christian Schoenebeck
5 schoenebeck 2515 *
6     * This program is part of LinuxSampler and released under the same terms.
7     */
8    
9     #include "KeyboardReader.h"
10    
11     static KeyboardReader* g_singleton = NULL;
12     static int g_instanceCount = 0;
13    
14     KeyboardReader::KeyboardReader() : Thread(false, false, 1, -1),
15     m_originalTerminalSetting(TerminalCtrl::now()),
16     m_callback(NULL), m_doCallback(true)
17     {
18     if (!g_instanceCount) g_singleton = this;
19     g_instanceCount++;
20     TerminalCtrl::echoInput(false);
21     }
22    
23     KeyboardReader::~KeyboardReader() {
24 schoenebeck 3290 StopThread();
25 schoenebeck 2515 TerminalCtrl::restore(m_originalTerminalSetting);
26     // ensures that no temporary copy objects delete the global reference
27     g_instanceCount--;
28     if (!g_instanceCount) g_singleton = NULL;
29     }
30    
31     void KeyboardReader::setCallback(Callback_t fn) {
32     m_callback = fn;
33     }
34    
35     void KeyboardReader::callback(bool b) {
36     m_doCallback = b;
37     }
38    
39     int KeyboardReader::Main() {
40 schoenebeck 3766 #if DEBUG
41     Thread::setNameOfCaller("KeyboardReader");
42     #endif
43    
44 schoenebeck 2515 while (true) {
45     std::vector<char> v = TerminalCtrl::getChars(1, 1);
46     if (!v.empty()) {
47 schoenebeck 3766 // prevent thread from being cancelled
48     // (e.g. to prevent deadlocks while holding mutex lock(s))
49     pushCancelable(false);
50    
51 schoenebeck 2515 m_fifoMutex.Lock();
52     m_fifo.push_back(v[0]);
53     if (m_sync.GetUnsafe()) {
54     bool delimiterReceived = false;
55     for (std::list<char>::iterator it = m_fifo.begin(); it != m_fifo.end(); ++it) {
56     if ((*it) == m_syncDelimiter) {
57     delimiterReceived = true;
58     break;
59     }
60     }
61     m_fifoMutex.Unlock();
62     if (delimiterReceived) m_sync.Set(false);
63     } else {
64     m_fifoMutex.Unlock();
65     if (m_callback && m_doCallback) (*m_callback)(this);
66     }
67 schoenebeck 3766
68     // now allow thread being cancelled again
69     // (since all mutexes are now unlocked)
70     popCancelable();
71 schoenebeck 2515 }
72     TestCancel();
73     }
74     return 0; // just to avoid a warning with some old compilers
75     }
76    
77     bool KeyboardReader::charAvailable() const {
78     return !m_fifo.empty(); // is thread safe
79     }
80    
81     char KeyboardReader::popChar() {
82     LockGuard lock(m_fifoMutex);
83     if (m_fifo.empty()) return 0;
84     char c = m_fifo.front();
85     m_fifo.pop_front();
86     return c;
87     }
88    
89     std::string KeyboardReader::popStringToDelimiterSync(char delimiter, bool includeDelimiter) {
90     m_syncDelimiter = delimiter;
91    
92     bool alreadyReceived = false;
93     m_fifoMutex.Lock();
94     for (std::list<char>::iterator it = m_fifo.begin(); it != m_fifo.end(); ++it) {
95     if ((*it)== delimiter) {
96     alreadyReceived = true;
97     break;
98     }
99     }
100     if (!alreadyReceived) m_sync.Set(true);
101     m_fifoMutex.Unlock();
102     if (!alreadyReceived) m_sync.WaitAndUnlockIf(true);
103    
104     // if we are here, then there is now a string with the requested delimiter
105     // in the FIFO
106     std::string s;
107     while (charAvailable()) {
108     char c = popChar();
109     if (includeDelimiter || c != delimiter) s += c;
110     if (c == delimiter) return s;
111     }
112     return s;
113     }
114    
115     void KeyboardReader::startReading() {
116     StartThread();
117     }
118    
119     void KeyboardReader::stopReading() {
120     StopThread();
121     }
122    
123     KeyboardReader* KeyboardReader::singleton() {
124     return g_singleton;
125     }

  ViewVC Help
Powered by ViewVC