AudioManager  7.5.11
Native Application Runtime Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
CAmSocketHandler.cpp
Go to the documentation of this file.
1 
24 #include "CAmSocketHandler.h"
25 #include <cassert>
26 #include <sys/fcntl.h>
27 #include <sys/errno.h>
28 #include <sys/poll.h>
29 #include <time.h>
30 #include <algorithm>
31 #include <features.h>
32 #include <csignal>
33 #include <unistd.h>
34 #include "CAmDltWrapper.h"
35 
36 namespace am
37 {
38 
40  receiverCallbackT(this, &CAmSocketHandler::receiverCallback),//
41  checkerCallbackT(this, &CAmSocketHandler::checkerCallback),//
42  mPipe(), //
43  mDispatchDone(1),//
44  mListPoll(), //
45  mListTimer(), //
46  mListActiveTimer(), //
47  mLastInsertedHandle(0), //
48  mLastInsertedPollHandle(0), //
49  mRecreatePollfds(true), //
50  mStartTime() //
51 {
52  if (pipe(mPipe) == -1)
53  {
54  logError("Sockethandler could not create pipe!");
55  }
56 
57  //add the pipe to the poll - nothing needs to be proccessed here we just need the pipe to trigger the ppoll
58  short event = 0;
59  sh_pollHandle_t handle;
60  event |= POLLIN;
61  addFDPoll(mPipe[0], event, NULL, &receiverCallbackT, &checkerCallbackT, NULL, NULL, handle);
62 }
63 
65 {
66  close(mPipe[0]);
67  close(mPipe[1]);
68 }
69 
70 //todo: maybe have some: give me more time returned?
75 {
76  mDispatchDone = 0;
77  int16_t pollStatus;
78 
79  //prepare the signalmask
80  sigset_t sigmask;
81  sigemptyset(&sigmask);
82  sigaddset(&sigmask, SIGINT);
83  sigaddset(&sigmask, SIGQUIT);
84  sigaddset(&sigmask, SIGTERM);
85  sigaddset(&sigmask, SIGHUP);
86  sigaddset(&sigmask, SIGQUIT);
87 
88  clock_gettime(CLOCK_MONOTONIC, &mStartTime);
89  while (!mDispatchDone)
90  {
91  //first we go through the registered filedescriptors and check if someone needs preparation:
92  std::for_each(mListPoll.begin(), mListPoll.end(), CAmShCallPrep());
93 
94  if (mRecreatePollfds)
95  {
96  mfdPollingArray.clear();
97  //there was a change in the setup, so we need to recreate the fdarray from the list
98  std::for_each(mListPoll.begin(), mListPoll.end(), CAmShCopyPollfd(mfdPollingArray));
99  mRecreatePollfds = false;
100  }
101 
102  timerCorrection();
103 
104  //block until something is on a filedescriptor
105 
106  timespec buffertime;
107  if ((pollStatus = ppoll(&mfdPollingArray[0], mfdPollingArray.size(), insertTime(buffertime), &sigmask)) < 0)
108  {
109  if (errno == EINTR)
110  {
111  //a signal was received, that means it's time to go...
112  pollStatus = 0;
113  }
114  else
115  {
116  logError("SocketHandler::start_listenting ppoll returned with error", errno);
117  throw std::runtime_error(std::string("SocketHandler::start_listenting ppoll returned with error."));
118  }
119  }
120 
121  if (pollStatus != 0) //only check filedescriptors if there was a change
122  {
123  //todo: here could be a timer that makes sure naughty plugins return!
124 
125  //freeze mListPoll by copying it - otherwise we get problems when we want to manipulate it during the next lines
126  std::list<sh_poll_s> listPoll;
127  mListPoll_t::iterator listmPollIt;
128 
129  //remove all filedescriptors who did not fire
130  std::vector<pollfd>::iterator it = mfdPollingArray.begin();
131  do
132  {
133  it = std::find_if(it, mfdPollingArray.end(), eventFired);
134  if (it != mfdPollingArray.end())
135  {
136  listmPollIt = mListPoll.begin();
137  std::advance(listmPollIt, std::distance(mfdPollingArray.begin(), it));
138  listPoll.push_back(*listmPollIt);
139  listPoll.back().pollfdValue = *it;
140  it++;
141  }
142  } while (it != mfdPollingArray.end());
143 
144  //stage 1, call firedCB
145  std::for_each(listPoll.begin(), listPoll.end(), CAmShCallFire());
146 
147  //stage 2, lets ask around if some dispatching is necessary, the ones who need stay on the list
148  listPoll.remove_if(noDispatching);
149 
150  //stage 3, the ones left need to dispatch, we do this as long as there is something to dispatch..
151  do
152  {
153  listPoll.remove_if(dispatchingFinished);
154  } while (!listPoll.empty());
155 
156  }
157  else //Timerevent
158  {
159  //this was a timer event, we need to take care about the timers
160  timerUp();
161  }
162  }
163 }
164 
169 {
170  mDispatchDone = 1;
171 
172  //this is for all running timers only - we need to handle the additional offset here
173  if (!mListActiveTimer.empty())
174  {
175  timespec currentTime, correctionTime;
176  clock_gettime(CLOCK_MONOTONIC, &currentTime);
177  correctionTime = timespecSub(currentTime, mStartTime);
178  std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), CAmShSubstractTime(correctionTime));
179  }
180 
181 }
182 
195 am_Error_e CAmSocketHandler::addFDPoll(const int fd, const short event, IAmShPollPrepare *prepare, IAmShPollFired *fired, IAmShPollCheck *check, IAmShPollDispatch *dispatch, void *userData, sh_pollHandle_t & handle)
196 {
197  if (!fdIsValid(fd))
198  return (E_NON_EXISTENT);
199 
200  //create a new handle for the poll
201  sh_pollHandle_t lastHandle(mLastInsertedPollHandle);
202  do
203  {
204  ++mLastInsertedPollHandle;
205  if (mLastInsertedPollHandle == MAX_POLLHANDLE)
206  {
207  mLastInsertedPollHandle = 1;
208  }
209  if (mLastInsertedPollHandle==lastHandle)
210  {
211  logError(__func__,"Could not create new polls, too many open!");
213  }
214 
215  } while (mSetPollKeys.find(mLastInsertedPollHandle) != mSetPollKeys.end());
216 
217  mSetPollKeys.insert(mLastInsertedPollHandle);
218 
219  sh_poll_s pollData;
220  pollData.pollfdValue.fd = fd;
221  pollData.handle = mLastInsertedPollHandle;
222  pollData.pollfdValue.events = event;
223  pollData.pollfdValue.revents = 0;
224  pollData.userData = userData;
225  pollData.prepareCB = prepare;
226  pollData.firedCB = fired;
227  pollData.checkCB = check;
228  pollData.dispatchCB = dispatch;
229 
230  //add new data to the list
231  mListPoll.push_back(pollData);
232 
233  mRecreatePollfds = true;
234 
235  handle = pollData.handle;
236  return (E_OK);
237 }
238 
245 {
246  mListPoll_t::iterator iterator = mListPoll.begin();
247 
248  for (; iterator != mListPoll.end(); ++iterator)
249  {
250  if (iterator->handle == handle)
251  {
252  iterator = mListPoll.erase(iterator);
253  mSetPollKeys.erase(handle);
254  mRecreatePollfds = true;
255  return (E_OK);
256  }
257  }
258  return (E_UNKNOWN);
259 }
260 
272 am_Error_e CAmSocketHandler::addTimer(const timespec timeouts, IAmShTimerCallBack* callback, sh_timerHandle_t& handle, void * userData)
273 {
274  assert(!((timeouts.tv_sec==0) && (timeouts.tv_nsec==0)));
275  assert(callback!=NULL);
276 
277  sh_timer_s timerItem;
278 
279  //create a new handle for the timer
280  sh_timerHandle_t lastTimerHandle(mLastInsertedHandle);
281  do
282  {
283  ++mLastInsertedHandle;
284  if (mLastInsertedHandle == MAX_TIMERHANDLE)
285  {
286  mLastInsertedHandle = 1;
287  }
288  if (lastTimerHandle==mLastInsertedHandle)
289  {
290  logError(__func__,"Could not create new timers, too many open!");
291  return (am_Error_e::E_NOT_POSSIBLE);
292  }
293 
294  } while (mSetTimerKeys.find(mLastInsertedHandle) != mSetTimerKeys.end());
295 
296  mSetTimerKeys.insert(mLastInsertedHandle);
297  handle=mLastInsertedHandle;
298  timerItem.handle = handle;
299  timerItem.countdown = timeouts;
300  timerItem.callback = callback;
301  timerItem.userData = userData;
302 
303  mListTimer.push_back(timerItem);
304 
305  //we add here the time difference between startTime and currenttime, because this time will be substracted later on in timecorrection
306  timespec currentTime;
307  clock_gettime(CLOCK_MONOTONIC, &currentTime);
308  if (!mDispatchDone) //the mainloop is started
309  timerItem.countdown = timespecAdd(timeouts, timespecSub(currentTime, mStartTime));
310 
311  mListActiveTimer.push_back(timerItem);
312  mListActiveTimer.sort(compareCountdown);
313  return (E_OK);
314 }
315 
322 {
323  assert(handle!=0);
324 
325  //stop the current timer
326  stopTimer(handle);
327 
328  std::list<sh_timer_s>::iterator it(mListTimer.begin());
329  for (; it != mListTimer.end(); ++it)
330  {
331  if (it->handle == handle)
332  {
333  it = mListTimer.erase(it);
334  mSetTimerKeys.erase(handle);
335  return (E_OK);
336  }
337  }
338  return (E_UNKNOWN);
339 }
340 
347 am_Error_e CAmSocketHandler::updateTimer(const sh_timerHandle_t handle, const timespec timeouts)
348 {
349  //update the mList ....
350  sh_timer_s timerItem;
351  std::list<sh_timer_s>::iterator it(mListTimer.begin()), activeIt(mListActiveTimer.begin());
352  bool found(false);
353  for (; it != mListTimer.end(); ++it)
354  {
355  if (it->handle == handle)
356  {
357  it->countdown = timeouts;
358  timerItem = *it;
359  found = true;
360  break;
361  }
362  }
363  if (!found)
364  return (E_NON_EXISTENT);
365 
366  found = false;
367 
368  //we add here the time difference between startTime and currenttime, because this time will be substracted later on in timecorrection
369  timespec currentTime, timeoutsCorrected;
370  currentTime.tv_nsec=timeoutsCorrected.tv_nsec=0;
371  currentTime.tv_sec=timeoutsCorrected.tv_sec=0;
372  clock_gettime(CLOCK_MONOTONIC, &currentTime);
373  if (!mDispatchDone) //the mainloop is started
374  timeoutsCorrected = timespecAdd(timeouts, timespecSub(currentTime, mStartTime));
375 
376  for (; activeIt != mListActiveTimer.end(); ++activeIt)
377  {
378  if (activeIt->handle == handle)
379  {
380  activeIt->countdown = timeoutsCorrected;
381  found = true;
382  break;
383  }
384  }
385 
386  if (!found)
387  timerItem.countdown = timeoutsCorrected;
388  mListActiveTimer.push_back(timerItem);
389 
390  mListActiveTimer.sort(compareCountdown);
391  return (E_OK);
392 }
393 
400 {
401  sh_timer_s timerItem;
402  //find the original value
403  std::list<sh_timer_s>::iterator it(mListTimer.begin()), activeIt(mListActiveTimer.begin());
404  bool found(false);
405  for (; it != mListTimer.end(); ++it)
406  {
407  if (it->handle == handle)
408  {
409  timerItem = *it;
410  found = true;
411  break;
412  }
413  }
414  if (!found)
415  return (E_NON_EXISTENT);
416 
417  found = false;
418 
419  //we add here the time difference between startTime and currenttime, because this time will be substracted later on in timecorrection
420  timespec currentTime, timeoutsCorrected;
421  clock_gettime(CLOCK_MONOTONIC, &currentTime);
422  if (!mDispatchDone) //the mainloop is started
423  {
424  timeoutsCorrected = timespecAdd(timerItem.countdown, timespecSub(currentTime, mStartTime));
425  timerItem.countdown = timeoutsCorrected;
426  }
427 
428  for (; activeIt != mListActiveTimer.end(); ++activeIt)
429  {
430  if (activeIt->handle == handle)
431  {
432  activeIt->countdown = timerItem.countdown;
433  found = true;
434  break;
435  }
436  }
437 
438  if (!found)
439  mListActiveTimer.push_back(timerItem);
440 
441  mListActiveTimer.sort(compareCountdown);
442 
443  return (E_OK);
444 }
445 
452 {
453  //go through the list and remove the timer with the handle
454  std::list<sh_timer_s>::iterator it(mListActiveTimer.begin());
455  for (; it != mListActiveTimer.end(); ++it)
456  {
457  if (it->handle == handle)
458  {
459  it = mListActiveTimer.erase(it);
460  return (E_OK);
461  }
462  }
463  return (E_NON_EXISTENT);
464 }
465 
473 {
474  mListPoll_t::iterator iterator = mListPoll.begin();
475 
476  for (; iterator != mListPoll.end(); ++iterator)
477  {
478  if (iterator->handle == handle)
479  {
480  iterator->pollfdValue.events = events;
481  mRecreatePollfds = true;
482  return (E_OK);
483  }
484  }
485  return (E_UNKNOWN);
486 }
487 
493 bool CAmSocketHandler::fdIsValid(const int fd) const
494 {
495  return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
496 }
497 
501 void CAmSocketHandler::timerUp()
502 {
503  //find out the timedifference to starttime
504  timespec currentTime, diffTime;
505  clock_gettime(CLOCK_MONOTONIC, &currentTime);
506  diffTime = timespecSub(currentTime, mStartTime);
507 
508  //now we need to substract the diffTime from all timers and see if they are up
509  std::list<sh_timer_s>::reverse_iterator overflowIter = std::find_if(mListActiveTimer.rbegin(), mListActiveTimer.rend(), CAmShCountdownUp(diffTime));
510 
511  //copy all fired timers into a list
512  std::vector<sh_timer_s> tempList(overflowIter, mListActiveTimer.rend());
513 
514  //erase all fired timers
515  std::list<sh_timer_s>::iterator it(overflowIter.base());
516  mListActiveTimer.erase(mListActiveTimer.begin(), it);
517 
518  //call the callbacks for the timers
519  std::for_each(tempList.begin(), tempList.end(), CAmShCallTimer());
520 }
521 
525 void CAmSocketHandler::timerCorrection()
526 {
527  //get the current time and calculate the correction value
528  timespec currentTime, correctionTime;
529  clock_gettime(CLOCK_MONOTONIC, &currentTime);
530  correctionTime = timespecSub(currentTime, mStartTime);
531  mStartTime = currentTime;
532 
533  if (!mListActiveTimer.empty())
534  {
535 
536  //subtract the correction value from all items in the list
537  std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), CAmShSubstractTime(correctionTime));
538 
539  //find the last occurrence of zero -> timer overflowed
540  std::list<sh_timer_s>::reverse_iterator overflowIter = std::find_if(mListActiveTimer.rbegin(), mListActiveTimer.rend(), CAmShCountdownZero());
541 
542  //only if a timer overflowed
543  if (overflowIter != mListActiveTimer.rend())
544  {
545  //copy all timers that need to be called to a new list
546  std::vector<sh_timer_s> tempList(overflowIter, mListActiveTimer.rend());
547 
548  //erase all fired timers
549  std::list<sh_timer_s>::iterator it(overflowIter.base());
550  mListActiveTimer.erase(mListActiveTimer.begin(), it);
551 
552  //call the callbacks for the timers
553  std::for_each(tempList.begin(), tempList.end(), CAmShCallTimer());
554  }
555  }
556 }
557 
559 {
560  //end the while loop
561  stop_listening();
562 
563  //fire the ending filedescriptor
564  int p(1);
565  ssize_t result = write(mPipe[1], &p, sizeof(p));
566 }
567 
573 inline timespec* CAmSocketHandler::insertTime(timespec& buffertime)
574 {
575  if (!mListActiveTimer.empty())
576  {
577  buffertime = mListActiveTimer.front().countdown;
578  return (&buffertime);
579  }
580  else
581  {
582  return (NULL);
583  }
584 }
585 
586 void CAmSocketHandler::CAmShCallFire::operator()(sh_poll_s& row)
587 {
588  try
589  {
590  row.firedCB->Call(row.pollfdValue, row.handle, row.userData);
591  }
592  catch (std::exception& e)
593  {
594  logError("Sockethandler: Exception in FireCallback,caught",e.what());
595  }
596 }
597 
598 void CAmSocketHandler::CAmShCallPrep::operator()(sh_poll_s& row)
599 {
600  if (row.prepareCB)
601  {
602  try
603  {
604  row.prepareCB->Call(row.handle, row.userData);
605  }
606  catch (std::exception& e)
607  {
608  logError("Sockethandler: Exception in Preparecallback,caught",e.what());
609  }
610  }
611 }
612 
613 void CAmSocketHandler::CAmShCallTimer::operator()(sh_timer_s& row)
614 {
615  try
616  {
617  row.callback->Call(row.handle, row.userData);
618  }
619  catch (std::exception& e)
620  {
621  logError("Sockethandler: Exception in Timercallback,caught",e.what());
622  }
623 }
624 
625 void CAmSocketHandler::CAmShCopyPollfd::operator()(const sh_poll_s& row)
626 {
627  pollfd temp = row.pollfdValue;
628  temp.revents = 0;
629  mArray.push_back(temp);
630 }
631 
632 bool CAmSocketHandler::CAmShCountdownUp::operator()(const sh_timer_s& row)
633 {
634  timespec sub = timespecSub(row.countdown, mDiffTime);
635  if (sub.tv_nsec == 0 && sub.tv_sec == 0)
636  return (true);
637  return (false);
638 }
639 
640 bool CAmSocketHandler::CAmShCountdownZero::operator()(const sh_timer_s& row)
641 {
642  if (row.countdown.tv_nsec == 0 && row.countdown.tv_sec == 0)
643  return (true);
644  return (false);
645 }
646 
647 
648 }
649 
the desired object is non existent
am_Error_e
the errors of the audiomanager.
prototype for poll fired callback
am_Error_e restartTimer(const sh_timerHandle_t handle)
restarts a timer with the original value
The am::CAmSocketHandler implements a mainloop for the AudioManager.
uint16_t sh_pollHandle_t
this is a handle for a filedescriptor to be used with the SocketHandler
am_Error_e addTimer(const timespec timeouts, IAmShTimerCallBack *callback, sh_timerHandle_t &handle, void *userData)
adds a timer to the list of timers.
SPDX license identifier: MPL-2.0.
TAmShPollFired< CAmSocketHandler > receiverCallbackT
prototype for poll check callback
am_Error_e removeFDPoll(const sh_pollHandle_t handle)
removes a filedescriptor from the poll loop
prototype for poll prepared callback
uint16_t sh_timerHandle_t
this is a handle for a timer to be used with the SocketHandler
am_Error_e removeTimer(const sh_timerHandle_t handle)
removes a timer from the list of timers
am_Error_e stopTimer(const sh_timerHandle_t handle)
stops a timer
am_Error_e addFDPoll(const int fd, const short event, IAmShPollPrepare *prepare, IAmShPollFired *fired, IAmShPollCheck *check, IAmShPollDispatch *dispatch, void *userData, sh_pollHandle_t &handle)
Adds a filedescriptor to the polling loop.
#define MAX_TIMERHANDLE
am_Error_e updateEventFlags(const sh_pollHandle_t handle, const short events)
updates the eventFlags of a poll
void start_listenting()
start the block listening for filedescriptors.
#define MAX_POLLHANDLE
prototype for dispatch callback
TAmShPollCheck< CAmSocketHandler > checkerCallbackT
the desired action is not possible
am_Error_e updateTimer(const sh_timerHandle_t handle, const timespec timeouts)
restarts a timer and updates with a new interva
SPDX license identifier: MPL-2.0.
void logError(T value, TArgs...args)
logs given values with errorlevel with the default context
prototype for the timer callback
no error - positive reply
void stop_listening()
exits the loop