OSDN Git Service

Moved various auxiliary macros into the MUtils library.
[lamexp/LameXP.git] / src / Global_IPC.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version, but always including the *additional*
9 // restrictions defined in the "License.txt" file.
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 along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 //
20 // http://www.gnu.org/licenses/gpl-2.0.txt
21 ///////////////////////////////////////////////////////////////////////////////
22
23 #include "Global.h"
24
25 //MUtils
26 #include <MUtils/Global.h>
27 #include <MUtils/Exception.h>
28
29 //Qt includes
30 #include <QSharedMemory>
31 #include <QSystemSemaphore>
32 #include <QWriteLocker>
33
34 ///////////////////////////////////////////////////////////////////////////////
35 // TYPES
36 ///////////////////////////////////////////////////////////////////////////////
37
38 static const size_t g_lamexp_ipc_slots = 128;
39
40 typedef struct
41 {
42         unsigned int command;
43         unsigned int reserved_1;
44         unsigned int reserved_2;
45         char parameter[4096];
46 }
47 lamexp_ipc_data_t;
48
49 typedef struct
50 {
51         unsigned int pos_write;
52         unsigned int pos_read;
53         lamexp_ipc_data_t data[g_lamexp_ipc_slots];
54 }
55 lamexp_ipc_t;
56
57 ///////////////////////////////////////////////////////////////////////////////
58 // GLOBAL VARS
59 ///////////////////////////////////////////////////////////////////////////////
60
61 //Shared memory
62 static const struct
63 {
64         char *sharedmem;
65         char *semaphore_read;
66         char *semaphore_read_mutex;
67         char *semaphore_write;
68         char *semaphore_write_mutex;
69 }
70 g_lamexp_ipc_uuid =
71 {
72         "{21A68A42-6923-43bb-9CF6-64BF151942EE}",
73         "{7A605549-F58C-4d78-B4E5-06EFC34F405B}",
74         "{60AA8D04-F6B8-497d-81EB-0F600F4A65B5}",
75         "{726061D5-1615-4B82-871C-75FD93458E46}",
76         "{1A616023-AA6A-4519-8AF3-F7736E899977}"
77 };
78 static struct
79 {
80         QSharedMemory *sharedmem;
81         QSystemSemaphore *semaphore_read;
82         QSystemSemaphore *semaphore_read_mutex;
83         QSystemSemaphore *semaphore_write;
84         QSystemSemaphore *semaphore_write_mutex;
85         QReadWriteLock lock;
86 }
87 g_lamexp_ipc_ptr;
88
89 ///////////////////////////////////////////////////////////////////////////////
90 // GLOBAL FUNCTIONS
91 ///////////////////////////////////////////////////////////////////////////////
92
93 /*
94  * Initialize IPC
95  */
96 int lamexp_init_ipc(void)
97 {
98         QWriteLocker writeLock(&g_lamexp_ipc_ptr.lock);
99         
100         if(g_lamexp_ipc_ptr.sharedmem && g_lamexp_ipc_ptr.semaphore_read && g_lamexp_ipc_ptr.semaphore_write && g_lamexp_ipc_ptr.semaphore_read_mutex && g_lamexp_ipc_ptr.semaphore_write_mutex)
101         {
102                 return 0;
103         }
104
105         g_lamexp_ipc_ptr.semaphore_read = new QSystemSemaphore(QString(g_lamexp_ipc_uuid.semaphore_read), 0);
106         g_lamexp_ipc_ptr.semaphore_write = new QSystemSemaphore(QString(g_lamexp_ipc_uuid.semaphore_write), 0);
107         g_lamexp_ipc_ptr.semaphore_read_mutex = new QSystemSemaphore(QString(g_lamexp_ipc_uuid.semaphore_read_mutex), 0);
108         g_lamexp_ipc_ptr.semaphore_write_mutex = new QSystemSemaphore(QString(g_lamexp_ipc_uuid.semaphore_write_mutex), 0);
109
110         if(g_lamexp_ipc_ptr.semaphore_read->error() != QSystemSemaphore::NoError)
111         {
112                 QString errorMessage = g_lamexp_ipc_ptr.semaphore_read->errorString();
113                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_read);
114                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_write);
115                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
116                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
117                 qFatal("Failed to create system smaphore: %s", MUTILS_UTF8(errorMessage));
118                 return -1;
119         }
120         if(g_lamexp_ipc_ptr.semaphore_write->error() != QSystemSemaphore::NoError)
121         {
122                 QString errorMessage = g_lamexp_ipc_ptr.semaphore_write->errorString();
123                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_read);
124                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_write);
125                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
126                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
127                 qFatal("Failed to create system smaphore: %s", MUTILS_UTF8(errorMessage));
128                 return -1;
129         }
130         if(g_lamexp_ipc_ptr.semaphore_read_mutex->error() != QSystemSemaphore::NoError)
131         {
132                 QString errorMessage = g_lamexp_ipc_ptr.semaphore_read_mutex->errorString();
133                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_read);
134                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_write);
135                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
136                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
137                 qFatal("Failed to create system smaphore: %s", MUTILS_UTF8(errorMessage));
138                 return -1;
139         }
140         if(g_lamexp_ipc_ptr.semaphore_write_mutex->error() != QSystemSemaphore::NoError)
141         {
142                 QString errorMessage = g_lamexp_ipc_ptr.semaphore_write_mutex->errorString();
143                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_read);
144                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_write);
145                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
146                 MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
147                 qFatal("Failed to create system smaphore: %s", MUTILS_UTF8(errorMessage));
148                 return -1;
149         }
150
151         g_lamexp_ipc_ptr.sharedmem = new QSharedMemory(QString(g_lamexp_ipc_uuid.sharedmem), NULL);
152         
153         if(!g_lamexp_ipc_ptr.sharedmem->create(sizeof(lamexp_ipc_t)))
154         {
155                 if(g_lamexp_ipc_ptr.sharedmem->error() == QSharedMemory::AlreadyExists)
156                 {
157                         g_lamexp_ipc_ptr.sharedmem->attach();
158                         if(g_lamexp_ipc_ptr.sharedmem->error() == QSharedMemory::NoError)
159                         {
160                                 return 1;
161                         }
162                         else
163                         {
164                                 QString errorMessage = g_lamexp_ipc_ptr.sharedmem->errorString();
165                                 MUTILS_DELETE(g_lamexp_ipc_ptr.sharedmem);
166                                 qFatal("Failed to attach to shared memory: %s", MUTILS_UTF8(errorMessage));
167                                 return -1;
168                         }
169                 }
170                 else
171                 {
172                         QString errorMessage = g_lamexp_ipc_ptr.sharedmem->errorString();
173                         MUTILS_DELETE(g_lamexp_ipc_ptr.sharedmem);
174                         qFatal("Failed to create shared memory: %s", MUTILS_UTF8(errorMessage));
175                         return -1;
176                 }
177         }
178
179         memset(g_lamexp_ipc_ptr.sharedmem->data(), 0, sizeof(lamexp_ipc_t));
180         g_lamexp_ipc_ptr.semaphore_write->release(g_lamexp_ipc_slots);
181         g_lamexp_ipc_ptr.semaphore_read_mutex->release();
182         g_lamexp_ipc_ptr.semaphore_write_mutex->release();
183
184         return 0;
185 }
186
187 /*
188  * IPC send message
189  */
190 void lamexp_ipc_send(unsigned int command, const char* message)
191 {
192         QReadLocker readLock(&g_lamexp_ipc_ptr.lock);
193
194         if(!g_lamexp_ipc_ptr.sharedmem || !g_lamexp_ipc_ptr.semaphore_read || !g_lamexp_ipc_ptr.semaphore_write || !g_lamexp_ipc_ptr.semaphore_read_mutex || !g_lamexp_ipc_ptr.semaphore_write_mutex)
195         {
196                 MUTILS_THROW("Shared memory for IPC not initialized yet.");
197         }
198
199         lamexp_ipc_data_t ipc_data;
200         memset(&ipc_data, 0, sizeof(lamexp_ipc_data_t));
201         ipc_data.command = command;
202         
203         if(message)
204         {
205                 strncpy_s(ipc_data.parameter, 4096, message, _TRUNCATE);
206         }
207
208         if(g_lamexp_ipc_ptr.semaphore_write->acquire())
209         {
210                 if(g_lamexp_ipc_ptr.semaphore_write_mutex->acquire())
211                 {
212                         lamexp_ipc_t *ptr = reinterpret_cast<lamexp_ipc_t*>(g_lamexp_ipc_ptr.sharedmem->data());
213                         memcpy(&ptr->data[ptr->pos_write], &ipc_data, sizeof(lamexp_ipc_data_t));
214                         ptr->pos_write = (ptr->pos_write + 1) % g_lamexp_ipc_slots;
215                         g_lamexp_ipc_ptr.semaphore_read->release();
216                         g_lamexp_ipc_ptr.semaphore_write_mutex->release();
217                 }
218         }
219 }
220
221 /*
222  * IPC read message
223  */
224 void lamexp_ipc_read(unsigned int *command, char* message, size_t buffSize)
225 {
226         QReadLocker readLock(&g_lamexp_ipc_ptr.lock);
227         
228         *command = 0;
229         message[0] = '\0';
230         
231         if(!g_lamexp_ipc_ptr.sharedmem || !g_lamexp_ipc_ptr.semaphore_read || !g_lamexp_ipc_ptr.semaphore_write || !g_lamexp_ipc_ptr.semaphore_read_mutex || !g_lamexp_ipc_ptr.semaphore_write_mutex)
232         {
233                 MUTILS_THROW("Shared memory for IPC not initialized yet.");
234         }
235
236         lamexp_ipc_data_t ipc_data;
237         memset(&ipc_data, 0, sizeof(lamexp_ipc_data_t));
238
239         if(g_lamexp_ipc_ptr.semaphore_read->acquire())
240         {
241                 if(g_lamexp_ipc_ptr.semaphore_read_mutex->acquire())
242                 {
243                         lamexp_ipc_t *ptr = reinterpret_cast<lamexp_ipc_t*>(g_lamexp_ipc_ptr.sharedmem->data());
244                         memcpy(&ipc_data, &ptr->data[ptr->pos_read], sizeof(lamexp_ipc_data_t));
245                         ptr->pos_read = (ptr->pos_read + 1) % g_lamexp_ipc_slots;
246                         g_lamexp_ipc_ptr.semaphore_write->release();
247                         g_lamexp_ipc_ptr.semaphore_read_mutex->release();
248
249                         if(!(ipc_data.reserved_1 || ipc_data.reserved_2))
250                         {
251                                 *command = ipc_data.command;
252                                 strncpy_s(message, buffSize, ipc_data.parameter, _TRUNCATE);
253                         }
254                         else
255                         {
256                                 qWarning("Malformed IPC message, will be ignored");
257                         }
258                 }
259         }
260 }
261
262 ///////////////////////////////////////////////////////////////////////////////
263 // INITIALIZATION
264 ///////////////////////////////////////////////////////////////////////////////
265
266 extern "C" void _lamexp_global_init_ipcom(void)
267 {
268         MUTILS_ZERO_MEMORY(g_lamexp_ipc_ptr);
269 }
270
271 ///////////////////////////////////////////////////////////////////////////////
272 // FINALIZATION
273 ///////////////////////////////////////////////////////////////////////////////
274
275 extern "C" void _lamexp_global_free_ipcom(void)
276 {
277         if(g_lamexp_ipc_ptr.sharedmem)
278         {
279                 g_lamexp_ipc_ptr.sharedmem->detach();
280         }
281
282         MUTILS_DELETE(g_lamexp_ipc_ptr.sharedmem);
283         MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_read);
284         MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_write);
285         MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_read_mutex);
286         MUTILS_DELETE(g_lamexp_ipc_ptr.semaphore_write_mutex);
287 }