Version 0.61. Move client allocation in JackEngine
[jack2.git] / windows / JackWinNamedPipeServerChannel.cpp
blob0a7e76a856139a2c41bc3505c38f937fb8924768
1 /*
2 Copyright (C) 2004-2006 Grame
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include "JackWinNamedPipeServerChannel.h"
21 #include "JackRequest.h"
22 #include "JackServer.h"
23 #include "JackEngine.h"
24 #include "JackGlobals.h"
25 #include "JackClient.h"
26 #include <assert.h>
28 using namespace std;
30 namespace Jack
33 HANDLE JackClientPipeThread::fMutex = NULL; // never released....
35 // fRefNum = -1 correspond to already removed client
37 JackClientPipeThread::JackClientPipeThread(JackWinNamedPipeClient* pipe)
38 : fPipe(pipe), fServer(NULL), fRefNum(0)
40 fThread = JackGlobals::MakeThread(this);
41 if (fMutex == NULL)
42 fMutex = CreateMutex(NULL, FALSE, NULL);
45 JackClientPipeThread::~JackClientPipeThread()
47 JackLog("JackClientPipeThread::~JackClientPipeThread\n");
48 delete fPipe;
49 delete fThread;
52 int JackClientPipeThread::Open(JackServer* server) // Open the Server/Client connection
54 fServer = server;
56 // Start listening
57 if (fThread->Start() != 0) {
58 jack_error("Cannot start Jack server listener\n");
59 return -1;
60 } else {
61 return 0;
65 void JackClientPipeThread::Close() // Close the Server/Client connection
67 JackLog("JackClientPipeThread::Close %x %ld\n", this, fRefNum);
69 TODO : solve WIN32 thread Kill issue
70 This would hang.. since Close will be followed by a delete,
71 all ressources will be desallocated at the end.
74 fThread->Kill();
75 fPipe->Close();
76 fRefNum = -1;
79 bool JackClientPipeThread::Execute()
81 JackLog("JackClientPipeThread::Execute\n");
82 return (HandleRequest() == 0);
85 int JackClientPipeThread::HandleRequest()
87 // Read header
88 JackRequest header;
89 int res = header.Read(fPipe);
90 int ret = 0;
92 // Lock the global mutex
93 if (WaitForSingleObject(fMutex, INFINITE) == WAIT_FAILED)
94 jack_error("JackClientPipeThread::HandleRequest: mutex wait error");
96 if (res < 0) {
97 jack_error("HandleRequest: cannot read header");
98 KillClient();
99 ret = -1;
100 } else {
102 // Read data
103 switch (header.fType) {
105 case JackRequest::kClientNew: {
106 JackLog("JackRequest::ClientNew\n");
107 JackClientNewRequest req;
108 JackClientNewResult res;
109 if (req.Read(fPipe) == 0)
110 AddClient(req.fName, &res.fSharedEngine, &res.fSharedClient, &res.fSharedPorts, &res.fResult);
111 res.Write(fPipe);
112 break;
115 case JackRequest::kClientClose: {
116 JackLog("JackRequest::ClientClose\n");
117 JackClientCloseRequest req;
118 JackResult res;
119 if (req.Read(fPipe) == 0)
120 res.fResult = fServer->GetEngine()->ClientClose(req.fRefNum);
121 res.Write(fPipe);
122 RemoveClient();
123 ret = -1;
124 break;
127 case JackRequest::kActivateClient: {
128 JackActivateRequest req;
129 JackResult res;
130 JackLog("JackRequest::ActivateClient\n");
131 if (req.Read(fPipe) == 0)
132 res.fResult = fServer->Activate(req.fRefNum);
133 res.Write(fPipe);
134 break;
137 case JackRequest::kDeactivateClient: {
138 JackLog("JackRequest::DeactivateClient\n");
139 JackDeactivateRequest req;
140 JackResult res;
141 if (req.Read(fPipe) == 0)
142 res.fResult = fServer->Deactivate(req.fRefNum);
143 res.Write(fPipe);
144 break;
147 case JackRequest::kRegisterPort: {
148 JackLog("JackRequest::RegisterPort\n");
149 JackPortRegisterRequest req;
150 JackPortRegisterResult res;
151 if (req.Read(fPipe) == 0)
152 res.fResult = fServer->GetEngine()->PortRegister(req.fRefNum, req.fName, req.fFlags, req.fBufferSize, &res.fPortIndex);
153 res.Write(fPipe);
154 break;
157 case JackRequest::kUnRegisterPort: {
158 JackLog("JackRequest::UnRegisterPort\n");
159 JackPortUnRegisterRequest req;
160 JackResult res;
161 if (req.Read(fPipe) == 0)
162 res.fResult = fServer->GetEngine()->PortUnRegister(req.fRefNum, req.fPortIndex);
163 res.Write(fPipe);
164 break;
167 case JackRequest::kConnectNamePorts: {
168 JackLog("JackRequest::ConnectPorts\n");
169 JackPortConnectNameRequest req;
170 JackResult res;
171 if (req.Read(fPipe) == 0)
172 res.fResult = fServer->GetEngine()->PortConnect(req.fRefNum, req.fSrc, req.fDst);
173 res.Write(fPipe);
174 break;
177 case JackRequest::kDisconnectNamePorts: {
178 JackLog("JackRequest::DisconnectPorts\n");
179 JackPortDisconnectNameRequest req;
180 JackResult res;
181 if (req.Read(fPipe) == 0)
182 res.fResult = fServer->GetEngine()->PortDisconnect(req.fRefNum, req.fSrc, req.fDst);
183 res.Write(fPipe);
184 break;
187 case JackRequest::kConnectPorts: {
188 JackLog("JackRequest::ConnectPorts\n");
189 JackPortConnectRequest req;
190 JackResult res;
191 if (req.Read(fPipe) == 0)
192 res.fResult = fServer->GetEngine()->PortConnect(req.fRefNum, req.fSrc, req.fDst);
193 res.Write(fPipe);
194 break;
197 case JackRequest::kDisconnectPorts: {
198 JackLog("JackRequest::DisconnectPorts\n");
199 JackPortDisconnectRequest req;
200 JackResult res;
201 if (req.Read(fPipe) == 0)
202 res.fResult = fServer->GetEngine()->PortDisconnect(req.fRefNum, req.fSrc, req.fDst);
203 res.Write(fPipe);
204 break;
207 case JackRequest::kSetBufferSize: {
208 JackLog("JackRequest::SetBufferSize\n");
209 JackSetBufferSizeRequest req;
210 JackResult res;
211 if (req.Read(fPipe) == 0)
212 res.fResult = fServer->SetBufferSize(req.fBufferSize);
213 res.Write(fPipe);
214 break;
217 case JackRequest::kSetFreeWheel: {
218 JackLog("JackRequest::SetFreeWheel\n");
219 JackSetFreeWheelRequest req;
220 JackResult res;
221 if (req.Read(fPipe) == 0)
222 res.fResult = fServer->SetFreewheel(req.fOnOff);
223 res.Write(fPipe);
224 break;
227 case JackRequest::kReleaseTimebase: {
228 JackLog("JackRequest::kReleaseTimebase\n");
229 JackReleaseTimebaseRequest req;
230 JackResult res;
231 if (req.Read(fPipe) == 0)
232 res.fResult = fServer->GetEngine()->ReleaseTimebase(req.fRefNum);
233 res.Write(fPipe);
234 break;
237 case JackRequest::kSetTimebaseCallback: {
238 JackLog("JackRequest::kSetTimebaseCallback\n");
239 JackSetTimebaseCallbackRequest req;
240 JackResult res;
241 if (req.Read(fPipe) == 0)
242 res.fResult = fServer->GetEngine()->SetTimebaseCallback(req.fRefNum, req.fConditionnal);
243 res.Write(fPipe);
244 break;
247 case JackRequest::kNotification: {
248 JackLog("JackRequest::Notification\n");
249 JackClientNotificationRequest req;
250 if (req.Read(fPipe) == 0)
251 fServer->Notify(req.fRefNum, req.fNotify, req.fValue);
252 break;
255 default:
256 JackLog("Unknown request %ld\n", header.fType);
257 break;
261 // Unlock the global mutex
262 ReleaseMutex(fMutex);
263 return ret;
266 void JackClientPipeThread::AddClient(char* name, int* shared_engine, int* shared_client, int* shared_ports, int* result)
268 JackLog("JackClientPipeThread::AddClient %s\n", name);
269 fRefNum = -1;
270 *result = fServer->GetEngine()->ClientNew(name, &fRefNum, shared_engine, shared_client, shared_ports);
273 void JackClientPipeThread::RemoveClient()
275 JackLog("JackClientPipeThread::RemoveClient ref = %d\n", fRefNum);
276 /* TODO : solve WIN32 thread Kill issue
277 Close();
279 fRefNum = -1;
280 fPipe->Close();
283 void JackClientPipeThread::KillClient()
285 JackLog("JackClientPipeThread::KillClient ref = %d\n", fRefNum);
287 if (fRefNum == -1) { // Correspond to an already removed client.
288 JackLog("Kill a closed client\n");
289 } else if (fRefNum == 0) { // Correspond to a still not opened client.
290 JackLog("Kill a not opened client\n");
291 } else {
292 fServer->Notify(fRefNum, JackNotifyChannelInterface::kDeadClient, 0);
295 Close();
298 JackWinNamedPipeServerChannel::JackWinNamedPipeServerChannel()
300 fThread = JackGlobals::MakeThread(this);
303 JackWinNamedPipeServerChannel::~JackWinNamedPipeServerChannel()
305 std::list<JackClientPipeThread*>::iterator it;
307 for (it = fClientList.begin(); it != fClientList.end(); it++) {
308 JackClientPipeThread* client = *it;
309 client->Close();
310 delete client;
313 delete fThread;
316 int JackWinNamedPipeServerChannel::Open(JackServer* server)
318 JackLog("JackWinNamedPipeServerChannel::Open \n");
320 fServer = server;
322 // Needed for internal connection from JackWinNamedPipeServerNotifyChannel object
323 if (fRequestListenPipe.Bind(jack_server_dir, 0) < 0) {
324 jack_error("JackWinNamedPipeServerChannel::Open : cannot create result listen pipe");
325 return false;
328 // Start listening
329 if (fThread->Start() != 0) {
330 jack_error("Cannot start Jack server listener\n");
331 goto error;
334 return 0;
336 error:
337 fRequestListenPipe.Close();
338 return -1;
341 void JackWinNamedPipeServerChannel::Close()
343 /* TODO : solve WIN32 thread Kill issue
344 This would hang the server... since we are quitting it, its not really problematic,
345 all ressources will be desallocated at the end.
347 fRequestListenPipe.Close();
348 fThread->Stop();
351 fThread->Kill();
352 fRequestListenPipe.Close();
355 bool JackWinNamedPipeServerChannel::Init()
357 JackLog("JackWinNamedPipeServerChannel::Init \n");
358 JackWinNamedPipeClient* pipe;
360 // Accept first client, that is the JackWinNamedPipeServerNotifyChannel object
361 if ((pipe = fRequestListenPipe.AcceptClient()) == NULL) {
362 jack_error("JackWinNamedPipeServerChannel::Init : cannot connect pipe");
363 return false;
364 } else {
365 AddClient(pipe);
366 return true;
370 bool JackWinNamedPipeServerChannel::Execute()
372 JackWinNamedPipeClient* pipe;
374 if (fRequestListenPipe.Bind(jack_server_dir, 0) < 0) {
375 jack_error("JackWinNamedPipeServerChannel::Open : cannot create result listen pipe");
376 return false;
379 if ((pipe = fRequestListenPipe.AcceptClient()) == NULL) {
380 jack_error("JackWinNamedPipeServerChannel::Open : cannot connect pipe");
381 return false;
384 AddClient(pipe);
385 return true;
388 void JackWinNamedPipeServerChannel::AddClient(JackWinNamedPipeClient* pipe)
390 // Remove dead (= not running anymore) clients.
391 std::list<JackClientPipeThread*>::iterator it = fClientList.begin();
392 JackClientPipeThread* client;
394 JackLog("AddClient size %ld\n", fClientList.size());
396 while (it != fClientList.end()) {
397 client = *it;
398 JackLog("Remove dead client = %x running = %ld\n", client, client->IsRunning());
399 if (client->IsRunning()) {
400 it++;
401 } else {
402 it = fClientList.erase(it);
403 delete client;
407 client = new JackClientPipeThread(pipe);
408 client->Open(fServer);
409 // Here we are sure that the client is running (because it's thread is in "running" state).
410 fClientList.push_back(client);
413 } // end of namespace