root/juggler/branches/2.2/modules/gadgeteer/gadget/DeviceServer.cpp

Revision 20291, 6.7 kB (checked in by patrick, 1 year ago)

Fixed a potential mutex deadlock. To do this, I changed the pre-condition of
gadget::DeviceServer::debugDump() so that mClientsLock must be held prior to
calling this method. This is not exactly ideal, but the alternative is to
reduce the exception safety guarantee of gadget::DeviceServer::send(), and
that seems like a much worse scenario.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*************** <auto-copyright.pl BEGIN do not edit this line> **************
2  *
3  * VR Juggler is (C) Copyright 1998-2007 by Iowa State University
4  *
5  * Original Authors:
6  *   Allen Bierbaum, Christopher Just,
7  *   Patrick Hartling, Kevin Meinert,
8  *   Carolina Cruz-Neira, Albert Baker
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  *
25  *************** <auto-copyright.pl END do not edit this line> ***************/
26
27 #include <gadget/gadgetConfig.h>
28 #include <boost/bind.hpp>
29 #include <gadget/Util/Debug.h>
30 #include <gadget/Node.h>
31 #include <gadget/DeviceServer.h>
32
33 namespace gadget
34 {
35    DeviceServer::DeviceServer(const std::string& name, gadget::Input* device,
36                               const vpr::GUID& plugin_guid)
37       : deviceServerTriggerSema(0)
38       , deviceServerDoneSema(0)
39    {
40       vpr::GUID temp;
41       temp.generate();
42
43       do
44       {
45          mId.generate();   // Generate a unique ID for this device
46          vprDEBUG(vprDBG_ALL, vprDBG_STATE_LVL)
47             << "[DeviceServer] Invalid GUID, generating a new one."
48             << std::endl << vprDEBUG_FLUSH;
49       }
50       while(temp == mId);
51
52       mThreadActive = false;
53       mName = name;
54       mDevice = device;
55       mPluginGUID = plugin_guid;
56
57       mDeviceData = new std::vector<vpr::Uint8>;
58       mDataPacket = new cluster::DataPacket(plugin_guid, mId, mDeviceData);
59       mBufferObjectWriter = new vpr::BufferObjectWriter(mDeviceData);
60    }
61
62    DeviceServer::~DeviceServer()
63    {
64       delete mDataPacket;
65       // mDataPacket will clean up the memory that mDeviceData points
66       // to since mDataPacket contains a reference to the ame memory.
67       mDeviceData = NULL;
68    }
69
70    void DeviceServer::send()
71    {
72       vpr::Guard<vpr::Mutex> guard(mClientsLock);
73
74       //vprDEBUG(gadgetDBG_RIM,vprDBG_CONFIG_LVL)
75       //   << clrOutBOLD(clrMAGENTA,"DeviceServer::send()")
76       //   << "Sending Device Data for: " << getName() << std::endl
77       //   << vprDEBUG_FLUSH;
78
79       for ( std::vector<gadget::Node*>::iterator i = mClients.begin();
80             i != mClients.end();
81             ++i )
82       {
83          //vprDEBUG(gadgetDBG_RIM,vprDBG_CONFIG_LVL)
84          //   << "Sending data to: " << (*i)->getName()
85          //   << " trying to lock socket" << std::endl << vprDEBUG_FLUSH;
86
87          try
88          {
89             (*i)->send(mDataPacket);
90          }
91          catch( cluster::ClusterException cluster_exception )
92          {
93             vprDEBUG( gadgetDBG_RIM, vprDBG_CONFIG_LVL )
94                << "DeviceServer::send() Caught an exception!"
95                << std::endl << vprDEBUG_FLUSH;
96             vprDEBUG( gadgetDBG_RIM, vprDBG_CONFIG_LVL )
97                << clrOutBOLD(clrRED, "ERROR:") << cluster_exception.what()
98                << std::endl << vprDEBUG_FLUSH;
99             vprDEBUG( gadgetDBG_RIM, vprDBG_CONFIG_LVL )
100                << "DeviceServer::send() We have lost our connection to: "
101                << (*i)->getName() << ":" << (*i)->getPort()
102                << std::endl << vprDEBUG_FLUSH;
103
104             (*i)->setStatus( gadget::Node::DISCONNECTED );
105             (*i)->shutdown();
106
107             debugDump( vprDBG_CONFIG_LVL );
108          }
109       }
110       //vprDEBUG(gadgetDBG_RIM,vprDBG_CONFIG_LVL)
111       //   << clrOutBOLD(clrMAGENTA,"DeviceServer::send()")
112       //   << "Done Sending Device Data for: " << getName() << std::endl
113       //   << vprDEBUG_FLUSH;
114    }
115
116    void DeviceServer::updateLocalData()
117    {
118       // -BufferObjectWriter
119       mBufferObjectWriter->getData()->clear();
120       mBufferObjectWriter->setCurPos(0);
121
122       // This updates the mDeviceData which both mBufferedObjectReader and
123       // mDevicePacket point to.
124       mDevice->writeObject(mBufferObjectWriter);
125
126       // We must update the size of the actual data that we are going to send
127       mDataPacket->getHeader()->setPacketLength(
128          cluster::Header::RIM_PACKET_HEAD_SIZE
129             + 16 /*Plugin GUID*/
130             + 16 /*Plugin GUID*/
131             + mDeviceData->size()
132       );
133
134       // We must serialize the header again so that we can reset the size.
135       mDataPacket->getHeader()->serializeHeader();
136    }
137
138    void DeviceServer::addClient(gadget::Node* new_client_node)
139    {
140       vprASSERT(new_client_node != NULL &&
141                 "You can not add a new client that is NULL");
142       vpr::Guard<vpr::Mutex> guard(mClientsLock);
143
144       mClients.push_back(new_client_node);
145    }
146
147    void DeviceServer::removeClient(const std::string& host_name)
148    {
149       vpr::Guard<vpr::Mutex> guard(mClientsLock);
150
151       for (std::vector<gadget::Node*>::iterator i = mClients.begin() ;
152             i!= mClients.end() ; i++)
153       {
154          if ((*i)->getHostname() == host_name)
155          {
156             mClients.erase(i);
157             return;
158          }
159       }
160    }
161
162    void DeviceServer::debugDump(int debugLevel)
163    {
164       vprASSERT(mClientsLock.test() &&
165                 "mClientsLock must be locked by the caller");
166
167       vpr::DebugOutputGuard dbg_output(
168          gadgetDBG_RIM, debugLevel,
169          "-------------- DeviceServer --------------\n",
170          "------------------------------------------\n"
171       );
172
173       vprDEBUG(gadgetDBG_RIM, debugLevel)
174          << "Name:     " << mName << std::endl << vprDEBUG_FLUSH;
175
176       { // Used simply to make the following DebugOutputGuard go out of scope
177          vpr::DebugOutputGuard dbg_output2(gadgetDBG_RIM, debugLevel,
178                            std::string("------------ Clients ------------\n"),
179                            std::string("---------------------------------\n"));
180          for ( std::vector<gadget::Node*>::iterator i = mClients.begin();
181                 i != mClients.end();
182                 ++i )
183          {
184             vprDEBUG(gadgetDBG_RIM, debugLevel)
185                << "-------- " << (*i)->getName() << " --------" << std::endl
186                << vprDEBUG_FLUSH;
187             vprDEBUG(gadgetDBG_RIM, debugLevel)
188                << "       Hostname: " << (*i)->getHostname() << std::endl
189                << vprDEBUG_FLUSH;
190             vprDEBUG(gadgetDBG_RIM, debugLevel)
191                << "----------------------------------" << std::endl
192                << vprDEBUG_FLUSH;
193          }
194       }
195    }
196 } // End of gadget namespace
197
Note: See TracBrowser for help on using the browser.