Beispiel #1
0
 public function startClock($interval, SignalHandler $sh = null, InputHandler $ih = null)
 {
     L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "Clock Started, interval %s", array($interval));
     $elapsed = 0.0;
     $start_time = microtime(true);
     $continue = true;
     while ($continue) {
         L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "Tick %s seconds", array($elapsed));
         $this->notifyTickObservers($elapsed);
         $processing_time = microtime(true) - $start_time;
         if ($processing_time > $interval) {
             L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, "Notification took %s, which is longer than interval %s", array($processing_time, $interval));
         } else {
             $this->sleep($interval - $processing_time);
         }
         $end_time = microtime(true);
         $elapsed = $end_time - $start_time;
         $start_time = $end_time;
         // test for exit condition via CTRL-C / SIGTERM
         if ($sh) {
             $sh->test();
             $continue = $continue && !$sh->shouldExit();
         }
         // test for exit condition via User Input
         if ($ih) {
             $ih->process();
             $continue = $continue && !$ih->shouldExit();
         }
         $continue = $continue && !$this->exit_notified;
     }
 }
Beispiel #2
0
 /**
  * Add a callback that listens to a specific signal.
  * @param string $signal_type
  * @param function $callback
  * @param int $priority
  */
 public function Listen($signal_type, $callback, $priority = 10)
 {
     if (!isset($this->listeners[$signal_type])) {
         $this->listeners[$signal_type] = array();
     }
     $this->listeners[$signal_type][] = array('callback' => $callback, 'priority' => $priority);
     $this->listeners[$signal_type] = SignalHandler::Sort($this->listeners[$signal_type], 'priority');
 }
Beispiel #3
0
 public static function start()
 {
     if (!extension_loaded('pcntl')) {
         return;
     }
     foreach (self::$handledSignals as $signal) {
         pcntl_signal($signal, function ($signal) {
             SignalHandler::$shouldExitForSignal = true;
         });
     }
 }
 /**
  * Calls signal handlers for pending signals.
  *
  * @return $this
  */
 public function dispatch()
 {
     $this->signalHandler->dispatch();
     return $this;
 }
 /**
  * Sets up and couples the event-driven history monitoring components, 
  * and then starts the clock.
  * 
  *  A signal handler is installed to catch Ctrl-C, although it's still
  *  safer to shutdown ScratchLive! first if you want everything scrobbled
  *  correctly.
  *  
  * --post-process can be used to replay a file. 
  * --manual to ticks on user input (for debugging. Overrides --post-process for ticks).
  * --csv can be used to replay from a CSV fake-file.
  * These options can be combined.
  * 
  */
 protected function monitor($filename)
 {
     // Use the caching version via Dependency Injection. This means that all
     // new SSLTracks created using a SSLTrackFactory will get a RuntimeCachingSSLTrack
     // that knows how to ask the cache about expensive lookups (such as getID3 stuff).
     Inject::map('SSLTrackFactory', new SSLTrackCache());
     if ($this->manual_tick) {
         // tick when the user presses enter
         $pseudo_ts = $real_ts = new CrankHandle();
     } elseif ($this->post_process) {
         $pseudo_ts = $real_ts = new InstantTickSource();
     } else {
         // tick based on the clock
         $pseudo_ts = $real_ts = new TickSource();
     }
     if ($this->post_process) {
         // $mon is TickObservable
         // $hfm is DiffObservable
         if ($this->csv) {
             $mon = $hfm = new SSLHistoryFileCSVInjector($filename);
         } else {
             $mon = $hfm = new SSLHistoryFileReplayer($filename);
         }
         $pseudo_ts = $mon;
         $hfm->addExitObserver($real_ts);
     } else {
         $mon = new TailMonitor();
         $mon->setFilenameSource($this);
         $hfm = new SSLHistoryFileMonitor($filename, $mon);
     }
     $sh = new SignalHandler();
     //$ih = new InputHandler();
     $rtm = new SSLRealtimeModel();
     $rtm_printer = new SSLRealtimeModelPrinter($rtm);
     $npm = new NowPlayingModel();
     $sm = new ScrobbleModel();
     // the ordering here is important. See the README.txt for a collaboration diagram.
     $pseudo_ts->addTickObserver($this->plugin_manager);
     $real_ts->addTickObserver($mon);
     $pseudo_ts->addTickObserver($npm);
     $hfm->addDiffObserver($rtm);
     $rtm->addTrackChangeObserver($rtm_printer);
     $rtm->addTrackChangeObserver($npm);
     $rtm->addTrackChangeObserver($sm);
     // get the PluginWrapper that wraps all other plugins.
     $pw = $this->plugin_manager->getObservers();
     // add all of the PluginWrappers to the various places.
     $pseudo_ts->addTickObserver($pw[0]);
     $hfm->addDiffObserver($pw[0]);
     $rtm->addTrackChangeObserver($pw[0]);
     $npm->addNowPlayingObserver($pw[0]);
     $sm->addScrobbleObserver($pw[0]);
     $sh->install();
     //$ih->install();
     $this->plugin_manager->onStart();
     // Tick tick tick. This only returns if a signal is caught
     $real_ts->startClock($this->sleep, $sh);
     $rtm->shutdown();
     $this->plugin_manager->onStop();
 }
 /**
  * Start Forking
  *
  * @param object $ProcessObject
  * @final 
  */
 public final function Run(&$ProcessObject)
 {
     // Check for ProcessObject existence
     if (!is_object($ProcessObject) || !$ProcessObject instanceof IProcess) {
         self::RaiseError("Invalid Proccess object", E_ERROR);
     }
     // Set class property
     $this->ProcessObject = $ProcessObject;
     $pid = posix_getpid();
     if ($this->PIDDir) {
         $this->Logger->debug("Touch process PID file {$pid}");
         @touch("{$this->PIDDir}/{$pid}");
     }
     $this->Logger->debug("Executing 'OnStartForking' routine");
     // Run routines before threading
     $this->ProcessObject->OnStartForking();
     $this->Logger->debug("'OnStartForking' successfully executed.");
     if (count($this->ProcessObject->ThreadArgs) != 0) {
         // Add handlers to signals
         $this->SignalHandler->SetSignalHandlers();
         $this->Logger->debug("Executing ProcessObject::ForkThreads()");
         // Start Threading
         $this->ForkThreads();
         // Wait while threads working
         $iteration = 1;
         while (true) {
             if (count($this->PIDs) == 0) {
                 break;
             }
             if ($this->ChildProcessExecTimeLimit != 0) {
                 foreach ($this->PIDs as $ipid => $ipid_info) {
                     if ($ipid_info['start_time'] + $this->ChildProcessExecTimeLimit < time()) {
                         $this->Logger->error(sprintf(_("Maximum execution time of %s seconds exceeded in %s. Killing process..."), $this->ChildProcessExecTimeLimit, get_class($this->ProcessObject) . "(Child PID: {$ipid_info['pid']})"));
                         posix_kill($ipid, SIGKILL);
                     }
                 }
             }
             sleep(2);
             if ($iteration++ == 10) {
                 $this->Logger->debug("Goin to MPWL. PIDs(" . implode(", ", array_keys($this->PIDs)) . ")");
                 //
                 // Zomby not needed.
                 //
                 $pid = pcntl_wait($status, WNOHANG | WUNTRACED);
                 if ($pid > 0) {
                     $this->Logger->debug("MPWL: pcntl_wait() from child with PID# {$pid} (Exit code: {$status})");
                     foreach ((array) $this->PIDs as $ipid => $ipid_info) {
                         if ($ipid == $pid) {
                             if ($this->PIDDir) {
                                 $this->Logger->debug("Delete thread PID file {$pid}");
                                 @unlink($this->PIDDir . "/" . $pid);
                             }
                             unset($this->PIDs[$ipid]);
                         }
                     }
                     $this->ForkThreads();
                 }
                 foreach ($this->PIDs as $ipid => $ipid_info) {
                     $res = posix_kill($ipid, 0);
                     $this->Logger->debug("MPWL: Sending 0 signal to {$ipid} = " . intval($res));
                     if ($res === FALSE) {
                         $this->Logger->debug("MPWL: Deleting '{$ipid}' from PIDs queue");
                         if ($this->PIDDir) {
                             $this->Logger->debug("Delete thread PID file {$ipid}");
                             @unlink($this->PIDDir . "/" . $ipid);
                         }
                         unset($this->PIDs[$ipid]);
                     }
                 }
                 $iteration = 1;
             }
         }
     } else {
         $this->Logger->debug("ProcessObject::ThreadArgs is empty. Nothing to do.");
     }
     $pid = posix_getpid();
     if ($this->PIDDir) {
         $this->Logger->debug("Delete Process PID file {$pid}");
         @unlink("{$this->PIDDir}/{$pid}");
     }
     $this->Logger->debug("All childs exited. Executing OnEndForking routine");
     // Run routines after forking
     $this->ProcessObject->OnEndForking();
     $this->Logger->debug("Main process complete. Exiting...");
     exit;
 }