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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3766 - (show annotations) (download)
Mon Apr 6 12:41:49 2020 UTC (4 years 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 /*
2 * LSCP Shell
3 *
4 * Copyright (c) 2014 - 2020 Christian Schoenebeck
5 *
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 StopThread();
25 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 #if DEBUG
41 Thread::setNameOfCaller("KeyboardReader");
42 #endif
43
44 while (true) {
45 std::vector<char> v = TerminalCtrl::getChars(1, 1);
46 if (!v.empty()) {
47 // prevent thread from being cancelled
48 // (e.g. to prevent deadlocks while holding mutex lock(s))
49 pushCancelable(false);
50
51 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
68 // now allow thread being cancelled again
69 // (since all mutexes are now unlocked)
70 popCancelable();
71 }
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