[cstdstring] demise Format, replacing with StringUtils::Format
[vuplus_xbmc] / xbmc / filesystem / PipesManager.cpp
1 /*
2  *      Copyright (C) 2011-2013 Team XBMC
3  *      http://xbmc.org
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, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "PipesManager.h"
22 #include "threads/SingleLock.h"
23 #include "utils/StringUtils.h"
24
25 #ifndef min
26 #define min(a,b) ((a) < (b) ? (a) : (b))
27 #endif
28
29 using namespace XFILE;
30
31
32 Pipe::Pipe(const CStdString &name, int nMaxSize)
33 {
34   m_buffer.Create(nMaxSize);
35   m_nRefCount = 1;
36   m_readEvent.Reset();
37   m_writeEvent.Set();
38   m_strPipeName = name;
39   m_bOpen = true;
40   m_bEof = false;
41   m_nOpenThreashold = PIPE_DEFAULT_MAX_SIZE / 2;
42   m_bReadyForRead = true; // open threashold disabled atm
43 }
44
45 Pipe::~Pipe()
46 {
47 }
48
49 void Pipe::SetOpenThreashold(int threashold)
50 {
51   m_nOpenThreashold = threashold;
52 }
53
54 const CStdString &Pipe::GetName() 
55 {
56   return m_strPipeName;
57 }
58
59 void Pipe::AddRef()
60 {
61   CSingleLock lock(m_lock);
62   m_nRefCount++;
63 }
64
65 void Pipe::DecRef()
66 {
67   CSingleLock lock(m_lock);
68   m_nRefCount--;
69 }
70
71 int  Pipe::RefCount()
72 {
73   CSingleLock lock(m_lock);
74   return m_nRefCount;
75 }
76
77 void Pipe::SetEof()
78 {
79   m_bEof = true;
80 }
81
82 bool Pipe::IsEof()
83 {
84   return m_bEof;
85 }
86
87 bool Pipe::IsEmpty()
88 {
89   return (m_buffer.getMaxReadSize() == 0);
90 }
91
92 void Pipe::Flush()
93 {
94   CSingleLock lock(m_lock);
95
96   if (!m_bOpen || !m_bReadyForRead || m_bEof)
97   {
98     return;
99   }
100   m_buffer.Clear();
101   CheckStatus();
102 }
103
104 int  Pipe::Read(char *buf, int nMaxSize, int nWaitMillis)
105 {
106   CSingleLock lock(m_lock);
107   
108   if (!m_bOpen)
109   {
110     return -1;
111   }
112
113   while (!m_bReadyForRead && !m_bEof)
114     m_readEvent.WaitMSec(100);
115
116   int nResult = 0;
117   if (!IsEmpty())
118   {
119     int nToRead = min((int)m_buffer.getMaxReadSize(), nMaxSize);
120     m_buffer.ReadData(buf, nToRead);
121     nResult = nToRead;
122   }
123   else if (m_bEof)
124   {
125     nResult = 0;
126   }
127   else
128   {
129     // we're leaving the guard - add ref to make sure we are not getting erased.
130     // at the moment we leave m_listeners unprotected which might be a problem in future
131     // but as long as we only have 1 listener attaching at startup and detaching on close we're fine
132     AddRef();
133     lock.Leave();
134
135     bool bHasData = false;
136     int nMillisLeft = nWaitMillis;
137     if (nMillisLeft < 0)
138       nMillisLeft = 5*60*1000; // arbitrary. 5 min.
139
140     do
141     {
142       for (size_t l=0; l<m_listeners.size(); l++)
143         m_listeners[l]->OnPipeUnderFlow();
144
145       bHasData = m_readEvent.WaitMSec(min(200,nMillisLeft));
146       nMillisLeft -= 200;
147     } while (!bHasData && nMillisLeft > 0 && !m_bEof);
148
149     lock.Enter();
150     DecRef();
151     
152     if (!m_bOpen)
153       return -1;
154     
155     if (bHasData)
156     {
157       int nToRead = min((int)m_buffer.getMaxReadSize(), nMaxSize);
158       m_buffer.ReadData(buf, nToRead);
159       nResult = nToRead;
160     }
161   }
162   
163   CheckStatus();
164   
165   return nResult;
166 }
167
168 bool Pipe::Write(const char *buf, int nSize, int nWaitMillis)
169 {
170   CSingleLock lock(m_lock);
171   if (!m_bOpen)
172     return false;
173   bool bOk = false;
174   int writeSize = m_buffer.getMaxWriteSize();
175   if (writeSize > nSize)
176   {
177     m_buffer.WriteData((char*)buf, nSize);
178     bOk = true;
179   }
180   else
181   {
182     while ( (int)m_buffer.getMaxWriteSize() < nSize && m_bOpen )
183     {
184       lock.Leave();
185       for (size_t l=0; l<m_listeners.size(); l++)
186         m_listeners[l]->OnPipeOverFlow();
187
188       bool bClear = nWaitMillis < 0 ? m_writeEvent.Wait() : m_writeEvent.WaitMSec(nWaitMillis);
189       lock.Enter();
190       if (bClear && (int)m_buffer.getMaxWriteSize() >= nSize)
191       {
192         m_buffer.WriteData((char*)buf, nSize);
193         bOk = true;
194         break;
195       }
196
197       // FIXME: is this right? Shouldn't we see if the time limit has been reached?
198       if (nWaitMillis > 0)
199         break;
200     }
201   }
202
203   CheckStatus();
204   
205   return bOk && m_bOpen;
206 }
207
208 void Pipe::CheckStatus()
209 {
210   if (m_bEof)
211   {
212     m_writeEvent.Set();
213     m_readEvent.Set();  
214     return;
215   }
216   
217   if (m_buffer.getMaxWriteSize() == 0)
218     m_writeEvent.Reset();
219   else
220     m_writeEvent.Set();
221   
222   if (m_buffer.getMaxReadSize() == 0)
223     m_readEvent.Reset();
224   else
225   {
226     if (!m_bReadyForRead  && (int)m_buffer.getMaxReadSize() >= m_nOpenThreashold)
227       m_bReadyForRead = true;
228     m_readEvent.Set();  
229   }
230 }
231
232 void Pipe::Close()
233 {
234   CSingleLock lock(m_lock);
235   m_bOpen = false;
236   m_readEvent.Set();
237   m_writeEvent.Set();
238 }
239
240 void Pipe::AddListener(IPipeListener *l)
241 {
242   CSingleLock lock(m_lock);
243   for (size_t i=0; i<m_listeners.size(); i++)
244   {
245     if (m_listeners[i] == l)
246       return;
247   }
248   m_listeners.push_back(l);
249 }
250
251 void Pipe::RemoveListener(IPipeListener *l)
252 {
253   CSingleLock lock(m_lock);
254   std::vector<XFILE::IPipeListener *>::iterator i = m_listeners.begin();
255   while(i != m_listeners.end())
256   {
257     if ( (*i) == l)
258       i = m_listeners.erase(i);
259     else
260       i++;
261   }
262 }
263
264 int     Pipe::GetAvailableRead()
265 {
266   CSingleLock lock(m_lock);
267   return m_buffer.getMaxReadSize();
268 }
269
270 PipesManager::PipesManager() : m_nGenIdHelper(1)
271 {
272 }
273
274 PipesManager::~PipesManager()
275 {
276 }
277
278 PipesManager &PipesManager::GetInstance()
279 {
280   static PipesManager instance;
281   return instance;
282 }
283
284 CStdString   PipesManager::GetUniquePipeName()
285 {
286   CSingleLock lock(m_lock);
287   return StringUtils::Format("pipe://%d/", m_nGenIdHelper++);
288 }
289
290 XFILE::Pipe *PipesManager::CreatePipe(const CStdString &name, int nMaxPipeSize)
291 {
292   CStdString pName = name;
293   if (pName.IsEmpty())
294     pName = GetUniquePipeName();
295   
296   CSingleLock lock(m_lock);
297   if (m_pipes.find(pName) != m_pipes.end())
298     return NULL;
299   
300   XFILE::Pipe *p = new XFILE::Pipe(pName, nMaxPipeSize);
301   m_pipes[pName] = p;
302   return p;
303 }
304
305 XFILE::Pipe *PipesManager::OpenPipe(const CStdString &name)
306 {
307   CSingleLock lock(m_lock);
308   if (m_pipes.find(name) == m_pipes.end())
309     return NULL;
310   m_pipes[name]->AddRef();
311   return m_pipes[name];
312 }
313
314 void         PipesManager::ClosePipe(XFILE::Pipe *pipe)
315 {
316   CSingleLock lock(m_lock);
317   if (!pipe)
318     return ;
319   
320   pipe->DecRef();
321   pipe->Close();
322   if (pipe->RefCount() == 0)
323   {
324     m_pipes.erase(pipe->GetName());
325     delete pipe;
326   }
327 }
328
329 bool         PipesManager::Exists(const CStdString &name)
330 {
331   CSingleLock lock(m_lock);
332   return (m_pipes.find(name) != m_pipes.end());
333 }
334