-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathclass.daemon.php
129 lines (114 loc) · 4.25 KB
/
class.daemon.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<?php
/*version 1.02
1.02 onLauncher puede devolver false, entonces no genera hijo. Util para controlar desde ese callback si debo hacer algo nuevo
*/
declare(ticks=1);
require "class.pidfile.php";
class Daemon{
public $maxProcesses = 10;
public $childsProcName = NULL;
public $keepWaiting=TRUE;
public $childObject=NULL;
public $pidFileDir="/var/run";
public $procName="daemon";
public $multiInstances=FALSE;
protected $currentJobs = array();
protected $signalQueue=array();
protected $parentPID;
private $listeners = array();
public function __construct($multi=FALSE){
$this->multiInstances=$multi;
$this->parentPID = getmypid();
pcntl_signal(SIGCHLD, array($this, "childSignalHandler"));
pcntl_signal(SIGHUP, array($this, "hupSignalHandler"));
pcntl_signal(SIGTERM, array($this, "termSignalHandler"));
}
public function run(){
$pidfile = new pidfile($this->pidFileDir,$this->procName);
if($pidfile->is_already_running() && $this->multiInstances==FALSE) {
$this->fire('onMultiInstance',array(&$this));
exit;
}
if(is_null($this->childsProcName)) $this->childsProcName="{$this->procName}_child.php";
while(TRUE===$this->keepWaiting) {
$jobID = rand(0,10000000000000);
while(count($this->currentJobs) >= $this->maxProcesses) sleep(1);
$launched = $this->launchJob($jobID);
}
while(count($this->currentJobs)) sleep(1);
$this->fire('onRunTerminated',array(&$this));
}
protected function launchJob($jobID){
if(FALSE===$this->fire('onLauncher',array(&$this))) {
usleep(20000);
return false;
}
$pid = pcntl_fork();
if($pid == -1){
$this->fire('onLaunchJobError',array(&$this));
return false;
}
else if ($pid){
$this->currentObjects[$pid]=$this->childObject;
$this->currentJobs[$pid] = $jobID;
if(isset($this->signalQueue[$pid])){
$this->childSignalHandler(SIGCHLD, $pid, $this->signalQueue[$pid]);
unset($this->signalQueue[$pid]);
}
}
else{
unset($this->currentObjects);
$exitStatus = 0;
setproctitle($this->childsProcName);
$this->fire('onLaunchJob',array(&$this));
exit($exitStatus);
}
return true;
}
public function hupSignalHandler() {
if( $this->parentPID == getmypid()) {
$this->fire('daemonHupSignalReceived',array(&$this));
foreach($this->currentJobs as $pid => $id) {
posix_kill($pid,SIGUSR1);
}
$this->fire('daemonHupSignalProcesed',array(&$this));
}
}
public function termSignalHandler() {
if( $this->parentPID == getmypid()) {
$this->fire('daemonTermSignalReceived',array(&$this));
foreach($this->currentJobs as $pid => $id) {
$this->fire('onChildTerminated',array(&$this,$pid));
posix_kill($pid,SIGKILL);
}
$this->fire('daemonTerminating',array(&$this));
exit(0);
}
}
public function childSignalHandler($signo, $pid=null, $status=null){
if(!$pid) $pid = pcntl_waitpid(-1, $status, WNOHANG);
while($pid > 0){
if($pid && isset($this->currentJobs[$pid])){
$exitCode = pcntl_wexitstatus($status);
$this->fire('onChildTerminated',array(&$this,$pid));
unset($this->currentObjects[$pid]);
unset($this->currentJobs[$pid]);
}
else if($pid) $this->signalQueue[$pid] = $status;
$pid = pcntl_waitpid(-1, $status, WNOHANG);
}
return true;
}
public function bind($event, $callback)
{
$this->listeners[$event][] = $callback;
}
public function fire($event, array $parameters)
{
if ( ! empty($this->listeners[$event])) {
foreach ($this->listeners[$event] as $listener) {
call_user_func_array($listener, $parameters);
}
}
}
}