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