LMMS
Loading...
Searching...
No Matches
RemotePluginBase.h
Go to the documentation of this file.
1/*
2 * RemotePluginBase.h - base class providing RPC like mechanisms
3 *
4 * Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
5 *
6 * This file is part of LMMS - https://lmms.io
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program (see COPYING); if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 USA.
22 *
23 */
24
25#ifndef LMMS_REMOTE_PLUGIN_BASE_H
26#define LMMS_REMOTE_PLUGIN_BASE_H
27
28#include <atomic> // IWYU pragma: keep
29#include <vector>
30#include <clocale> // IWYU pragma: keep
31#include <cstdio>
32#include <cstdlib>
33#include <cstring>
34#include <string>
35
36#include "lmmsconfig.h"
37
38#if !(defined(LMMS_HAVE_SYS_IPC_H) && defined(LMMS_HAVE_SEMAPHORE_H))
39#define SYNC_WITH_SHM_FIFO
40
41#ifdef LMMS_HAVE_PROCESS_H
42#include <process.h>
43#endif
44#else // !(LMMS_HAVE_SYS_IPC_H && LMMS_HAVE_SEMAPHORE_H)
45#ifdef LMMS_HAVE_UNISTD_H
46#include <unistd.h>
47#endif
48#endif // !(LMMS_HAVE_SYS_IPC_H && LMMS_HAVE_SEMAPHORE_H)
49
50#ifdef LMMS_HAVE_PTHREAD_H
51#include <pthread.h>
52#endif
53
54
55#ifdef BUILD_REMOTE_PLUGIN_CLIENT
56#undef LMMS_EXPORT
57#define LMMS_EXPORT
58
59#ifndef SYNC_WITH_SHM_FIFO
60#include <sys/socket.h>
61#include <sys/un.h>
62#endif // SYNC_WITH_SHM_FIFO
63
64#else // BUILD_REMOTE_PLUGIN_CLIENT
65#include "lmms_export.h"
66#include <QString>
67
68#ifndef SYNC_WITH_SHM_FIFO
69#include <poll.h>
70#include <unistd.h> // IWYU pragma: keep
71#endif // SYNC_WITH_SHM_FIFO
72
73#endif // BUILD_REMOTE_PLUGIN_CLIENT
74
75#ifdef SYNC_WITH_SHM_FIFO
76#include "SharedMemory.h"
77#include "SystemSemaphore.h"
78#endif
79
80namespace lmms
81{
82
83
84#ifdef SYNC_WITH_SHM_FIFO
85
86
87// sometimes we need to exchange bigger messages (e.g. for VST parameter dumps)
88// so set a usable value here
89const int SHM_FIFO_SIZE = 512*1024;
90
91
92// implements a FIFO inside a shared memory segment
93class shmFifo
94{
95 // need this union to handle different sizes of sem_t on 32 bit
96 // and 64 bit platforms
97 union sem32_t
98 {
99 int semKey;
100 char fill[32];
101 } ;
102 struct shmData
103 {
104 sem32_t dataSem; // semaphore for locking this
105 // FIFO management data
106 sem32_t messageSem; // semaphore for incoming messages
107 int32_t startPtr; // current start of FIFO in memory
108 int32_t endPtr; // current end of FIFO in memory
109 char data[SHM_FIFO_SIZE]; // actual data
110 } ;
111
112public:
113#ifndef BUILD_REMOTE_PLUGIN_CLIENT
114 // constructor for master-side
115 shmFifo() :
116 m_invalid( false ),
117 m_master( true ),
118 m_lockDepth( 0 )
119 {
120 m_data.create();
121 m_data->startPtr = m_data->endPtr = 0;
122 static int k = 0;
123 m_data->dataSem.semKey = ( getpid()<<10 ) + ++k;
124 m_data->messageSem.semKey = ( getpid()<<10 ) + ++k;
125 m_dataSem = SystemSemaphore{std::to_string(m_data->dataSem.semKey), 1u};
126 m_messageSem = SystemSemaphore{std::to_string(m_data->messageSem.semKey), 0u};
127 }
128#endif
129
130 // constructor for remote-/client-side - use _shm_key for making up
131 // the connection to master
132 shmFifo(const std::string& shmKey) :
133 m_invalid( false ),
134 m_master( false ),
135 m_lockDepth( 0 )
136 {
137 m_data.attach(shmKey);
138 m_dataSem = SystemSemaphore{std::to_string(m_data->dataSem.semKey)};
139 m_messageSem = SystemSemaphore{std::to_string(m_data->messageSem.semKey)};
140 }
141
142 inline bool isInvalid() const
143 {
144 return m_invalid;
145 }
146
147 void invalidate()
148 {
149 m_invalid = true;
150 }
151
152 // do we act as master (i.e. not as remote-process?)
153 inline bool isMaster() const
154 {
155 return m_master;
156 }
157
158 // recursive lock
159 inline void lock()
160 {
161 if( !isInvalid() && m_lockDepth.fetch_add( 1 ) == 0 )
162 {
163 m_dataSem.acquire();
164 }
165 }
166
167 // recursive unlock
168 inline void unlock()
169 {
170 if( m_lockDepth.fetch_sub( 1 ) <= 1 )
171 {
172 m_dataSem.release();
173 }
174 }
175
176 // wait until message-semaphore is available
177 inline void waitForMessage()
178 {
179 if( !isInvalid() )
180 {
181 m_messageSem.acquire();
182 }
183 }
184
185 // increase message-semaphore
186 inline void messageSent()
187 {
188 m_messageSem.release();
189 }
190
191
192 inline int32_t readInt()
193 {
194 int32_t i;
195 read( &i, sizeof( i ) );
196 return i;
197 }
198
199 inline void writeInt( const int32_t & _i )
200 {
201 write( &_i, sizeof( _i ) );
202 }
203
204 std::string readString()
205 {
206 std::string ret;
207 const int len = readInt();
208 if (len > 0)
209 {
210 ret.resize(static_cast<std::size_t>(len));
211 read(ret.data(), len);
212 ret[len] = '\0';
213 }
214 return ret;
215 }
216
217
218 inline void writeString( const std::string & _s )
219 {
220 const int len = _s.size();
221 writeInt( len );
222 write( _s.c_str(), len );
223 }
224
225
226 inline bool messagesLeft()
227 {
228 if( isInvalid() )
229 {
230 return false;
231 }
232 lock();
233 const bool empty = ( m_data->startPtr == m_data->endPtr );
234 unlock();
235 return !empty;
236 }
237
238
239 const std::string& shmKey() const
240 {
241 return m_data.key();
242 }
243
244
245private:
246 void read( void * _buf, int _len )
247 {
248 if( isInvalid() )
249 {
250 memset( _buf, 0, _len );
251 return;
252 }
253 lock();
254 while( isInvalid() == false &&
255 _len > m_data->endPtr - m_data->startPtr )
256 {
257 unlock();
258#ifndef LMMS_BUILD_WIN32
259 usleep( 5 );
260#endif
261 lock();
262 }
263 std::memcpy(_buf, m_data->data + m_data->startPtr, _len);
264 m_data->startPtr += _len;
265 // nothing left?
266 if( m_data->startPtr == m_data->endPtr )
267 {
268 // then reset to 0
269 m_data->startPtr = m_data->endPtr = 0;
270 }
271 unlock();
272 }
273
274 void write( const void * _buf, int _len )
275 {
276 if( isInvalid() || _len > SHM_FIFO_SIZE )
277 {
278 return;
279 }
280 lock();
281 while( _len > SHM_FIFO_SIZE - m_data->endPtr )
282 {
283 // if no space is left, try to move data to front
284 if( m_data->startPtr > 0 )
285 {
286 memmove( m_data->data,
287 m_data->data + m_data->startPtr,
288 m_data->endPtr - m_data->startPtr );
289 m_data->endPtr = m_data->endPtr -
290 m_data->startPtr;
291 m_data->startPtr = 0;
292 }
293 unlock();
294#ifndef LMMS_BUILD_WIN32
295 usleep( 5 );
296#endif
297 lock();
298 }
299 std::memcpy(m_data->data + m_data->endPtr, _buf, _len);
300 m_data->endPtr += _len;
301 unlock();
302 }
303
304 volatile bool m_invalid;
305 bool m_master;
306 SharedMemory<shmData> m_data;
307 SystemSemaphore m_dataSem;
308 SystemSemaphore m_messageSem;
309 std::atomic_int m_lockDepth;
310};
311#endif // SYNC_WITH_SHM_FIFO
312
313
314
346
347
348
349class LMMS_EXPORT RemotePluginBase
350{
351public:
352 struct message
353 {
355 id( IdUndefined ),
356 data()
357 {
358 }
359
360 message( const message & _m ) = default;
361
362 message( int _id ) :
363 id( _id ),
364 data()
365 {
366 }
367
368 template<class... Args>
369 message& addString(Args&&... args)
370 {
371 data.emplace_back(std::forward<Args>(args)...);
372 return *this;
373 }
374
375 message & addInt( int _i )
376 {
377 char buf[32];
378 std::snprintf(buf, 32, "%d", _i);
379 data.emplace_back( buf );
380 return *this;
381 }
382
383 message & addFloat( float _f )
384 {
385 char buf[32];
386 std::snprintf(buf, 32, "%f", _f);
387 data.emplace_back( buf );
388 return *this;
389 }
390
391 inline std::string getString( int _p = 0 ) const
392 {
393 return data[_p];
394 }
395
396#ifndef BUILD_REMOTE_PLUGIN_CLIENT
397 inline QString getQString( int _p = 0 ) const
398 {
399 return QString::fromStdString( getString( _p ) );
400 }
401#endif
402
403 inline int getInt( int _p = 0 ) const
404 {
405 return atoi( data[_p].c_str() );
406 }
407
408 inline float getFloat( int _p ) const
409 {
410 return (float) atof( data[_p].c_str() );
411 }
412
413 inline bool operator==( const message & _m ) const
414 {
415 return( id == _m.id );
416 }
417
418 int id;
419
420 private:
421 std::vector<std::string> data;
422
423 friend class RemotePluginBase;
424
425 } ;
426
427#ifdef SYNC_WITH_SHM_FIFO
428 RemotePluginBase( shmFifo * _in, shmFifo * _out );
429#else
431#endif
433
434#ifdef SYNC_WITH_SHM_FIFO
435 void reset( shmFifo *in, shmFifo *out )
436 {
437 delete m_in;
438 delete m_out;
439 m_in = in;
440 m_out = out;
441 }
442#endif
443
444 int sendMessage( const message & _m );
446
447 inline bool isInvalid() const
448 {
449#ifdef SYNC_WITH_SHM_FIFO
450 return m_in->isInvalid() || m_out->isInvalid();
451#else
452 return m_invalid;
453#endif
454 }
455
457 bool _busy_waiting = false );
458
460 {
462 processMessage( m );
463 return m;
464 }
465
466#ifndef SYNC_WITH_SHM_FIFO
468 {
469 int32_t i;
470 read( &i, sizeof( i ) );
471 return i;
472 }
473
474 inline void writeInt( const int32_t & _i )
475 {
476 write( &_i, sizeof( _i ) );
477 }
478
479 std::string readString()
480 {
481 std::string ret;
482 const int len = readInt();
483 if (len > 0)
484 {
485 ret.resize(static_cast<std::size_t>(len));
486 read(ret.data(), len);
487 ret[len] = '\0';
488 }
489 return ret;
490 }
491
492
493 inline void writeString( const std::string & _s )
494 {
495 const int len = _s.size();
496 writeInt( len );
497 write( _s.c_str(), len );
498 }
499#endif // SYNC_WITH_SHM_FIFO
500
501#ifndef BUILD_REMOTE_PLUGIN_CLIENT
502 inline bool messagesLeft()
503 {
504#ifdef SYNC_WITH_SHM_FIFO
505 return m_in->messagesLeft();
506#else
507 struct pollfd pollin;
508 pollin.fd = m_socket;
509 pollin.events = POLLIN;
510
511 if ( poll( &pollin, 1, 0 ) == -1 )
512 {
513 qWarning( "Unexpected poll error." );
514 }
515 return pollin.revents & POLLIN;
516#endif
517 }
518
520 {
521 while( messagesLeft() )
522 {
524 }
525 }
526
528 {
529 return waitDepthCounter() > 0;
530 }
531#endif // BUILD_REMOTE_PLUGIN_CLIENT
532
533 virtual bool processMessage( const message & _m ) = 0;
534
535
536protected:
537#ifdef SYNC_WITH_SHM_FIFO
538 inline const shmFifo * in() const
539 {
540 return m_in;
541 }
542
543 inline const shmFifo * out() const
544 {
545 return m_out;
546 }
547#endif
548
549 inline void invalidate()
550 {
551#ifdef SYNC_WITH_SHM_FIFO
552 m_in->invalidate();
553 m_out->invalidate();
554 m_in->messageSent();
555#else
556 m_invalid = true;
557#endif
558 }
559
560
561#ifndef SYNC_WITH_SHM_FIFO
563#endif
564
565
566private:
567#ifndef BUILD_REMOTE_PLUGIN_CLIENT
568 static int & waitDepthCounter()
569 {
570 static int waitDepth = 0;
571 return waitDepth;
572 }
573#endif
574
575#ifdef SYNC_WITH_SHM_FIFO
576 shmFifo * m_in;
577 shmFifo * m_out;
578#else
579 void read( void * _buf, int _len )
580 {
581 if( isInvalid() )
582 {
583 memset( _buf, 0, _len );
584 return;
585 }
586 char * buf = (char *) _buf;
587 int remaining = _len;
588 while ( remaining )
589 {
590 ssize_t nread = ::read( m_socket, buf, remaining );
591 switch ( nread )
592 {
593 case -1:
594 fprintf( stderr,
595 "Error while reading.\n" );
596 case 0:
597 invalidate();
598 memset( _buf, 0, _len );
599 return;
600 }
601 buf += nread;
602 remaining -= nread;
603 }
604 }
605
606 void write( const void * _buf, int _len )
607 {
608 if( isInvalid() )
609 {
610 return;
611 }
612 const char * buf = (const char *) _buf;
613 int remaining = _len;
614 while ( remaining )
615 {
616 ssize_t nwritten = ::write( m_socket, buf, remaining );
617 switch ( nwritten )
618 {
619 case -1:
620 fprintf( stderr,
621 "Error while writing.\n" );
622 case 0:
623 invalidate();
624 return;
625 }
626 buf += nwritten;
627 remaining -= nwritten;
628 }
629 }
630
631
633
634 pthread_mutex_t m_receiveMutex;
635 pthread_mutex_t m_sendMutex;
636#endif // SYNC_WITH_SHM_FIFO
637
638} ;
639
640} // namespace lmms
641
642#endif // LMMS_REMOTE_PLUGIN_BASE_H
static bool isMainThreadWaiting()
Definition RemotePluginBase.h:527
int sendMessage(const message &_m)
int32_t readInt()
Definition RemotePluginBase.h:467
int m_socket
Definition RemotePluginBase.h:562
void invalidate()
Definition RemotePluginBase.h:549
bool m_invalid
Definition RemotePluginBase.h:632
message fetchAndProcessNextMessage()
Definition RemotePluginBase.h:459
virtual bool processMessage(const message &_m)=0
bool messagesLeft()
Definition RemotePluginBase.h:502
void write(const void *_buf, int _len)
Definition RemotePluginBase.h:606
void writeString(const std::string &_s)
Definition RemotePluginBase.h:493
pthread_mutex_t m_receiveMutex
Definition RemotePluginBase.h:634
void fetchAndProcessAllMessages()
Definition RemotePluginBase.h:519
static int & waitDepthCounter()
Definition RemotePluginBase.h:568
pthread_mutex_t m_sendMutex
Definition RemotePluginBase.h:635
void read(void *_buf, int _len)
Definition RemotePluginBase.h:579
void writeInt(const int32_t &_i)
Definition RemotePluginBase.h:474
bool isInvalid() const
Definition RemotePluginBase.h:447
message waitForMessage(const message &_m, bool _busy_waiting=false)
std::string readString()
Definition RemotePluginBase.h:479
unsigned * m
Definition inflate.c:1559
register unsigned k
Definition inflate.c:946
struct huft * u[BMAX]
Definition inflate.c:1583
register unsigned i
Definition inflate.c:1575
JSAMPIMAGE data
Definition jpeglib.h:945
float in
Definition lilv_test.c:1460
float out
Definition lilv_test.c:1461
int int32_t
Definition mid.cpp:97
void fill(Buf &buf, T value)
Definition buffer.h:50
Definition AudioAlsa.cpp:35
RemoteMessageIDs
Definition RemotePluginBase.h:316
@ IdSaveSettingsToString
Definition RemotePluginBase.h:336
@ IdDebugMessage
Definition RemotePluginBase.h:342
@ IdSyncKey
Definition RemotePluginBase.h:321
@ IdMidiEvent
Definition RemotePluginBase.h:325
@ IdBufferSizeInformation
Definition RemotePluginBase.h:323
@ IdChangeInputOutputCount
Definition RemotePluginBase.h:331
@ IdLoadSettingsFromString
Definition RemotePluginBase.h:338
@ IdStartProcessing
Definition RemotePluginBase.h:326
@ IdChangeSharedMemoryKey
Definition RemotePluginBase.h:328
@ IdProcessingDone
Definition RemotePluginBase.h:327
@ IdInitDone
Definition RemotePluginBase.h:319
@ IdToggleUI
Definition RemotePluginBase.h:334
@ IdSavePresetFile
Definition RemotePluginBase.h:340
@ IdUndefined
Definition RemotePluginBase.h:317
@ IdLoadPresetFile
Definition RemotePluginBase.h:341
@ IdIdle
Definition RemotePluginBase.h:343
@ IdSaveSettingsToFile
Definition RemotePluginBase.h:337
@ IdHostInfoGotten
Definition RemotePluginBase.h:318
@ IdChangeOutputCount
Definition RemotePluginBase.h:330
@ IdQuit
Definition RemotePluginBase.h:320
@ IdIsUIVisible
Definition RemotePluginBase.h:335
@ IdHideUI
Definition RemotePluginBase.h:333
@ IdLoadSettingsFromFile
Definition RemotePluginBase.h:339
@ IdInformationUpdated
Definition RemotePluginBase.h:324
@ IdSampleRateInformation
Definition RemotePluginBase.h:322
@ IdUserBase
Definition RemotePluginBase.h:344
@ IdShowUI
Definition RemotePluginBase.h:332
@ IdChangeInputCount
Definition RemotePluginBase.h:329
#define true
Definition ordinals.h:82
#define false
Definition ordinals.h:83
Definition RemotePluginBase.h:353
message(const message &_m)=default
message()
Definition RemotePluginBase.h:354
message & addString(Args &&... args)
Definition RemotePluginBase.h:369
std::vector< std::string > data
Definition RemotePluginBase.h:421
message & addFloat(float _f)
Definition RemotePluginBase.h:383
QString getQString(int _p=0) const
Definition RemotePluginBase.h:397
std::string getString(int _p=0) const
Definition RemotePluginBase.h:391
bool operator==(const message &_m) const
Definition RemotePluginBase.h:413
int getInt(int _p=0) const
Definition RemotePluginBase.h:403
int id
Definition RemotePluginBase.h:418
friend class RemotePluginBase
Definition RemotePluginBase.h:423
message & addInt(int _i)
Definition RemotePluginBase.h:375
float getFloat(int _p) const
Definition RemotePluginBase.h:408
message(int _id)
Definition RemotePluginBase.h:362
read(f, &c, 1)