summaryrefslogtreecommitdiffabout
path: root/lib/process_manager.cc
Unidiff
Diffstat (limited to 'lib/process_manager.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--lib/process_manager.cc152
1 files changed, 152 insertions, 0 deletions
diff --git a/lib/process_manager.cc b/lib/process_manager.cc
new file mode 100644
index 0000000..48bcb03
--- a/dev/null
+++ b/lib/process_manager.cc
@@ -0,0 +1,152 @@
1#ifdef USE_PCH
2 #include "pch.h"
3#else
4 #include <sys/types.h>
5 #include <unistd.h>
6 #include <sys/wait.h>
7 #include <signal.h>
8 #include <errno.h>
9 #include <cassert>
10 #include <string>
11 #include <konforka/exception.h>
12 using namespace std;
13 #include "sitecing/process_manager.h"
14#endif
15
16namespace sitecing {
17
18 process_manager::process_manager()
19 : min_children(1), max_children(MAX_SITECING_SCOREBOARD_SLOTS),
20 min_spare_children(0), max_spare_children(-1), finishing(false),
21 die_humbly(false) {
22 }
23 process_manager::~process_manager() {
24 if(die_humbly)
25 return;
26 for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
27 scoreboard_slot *sslot = sboard.get_slot(tmp);
28 if((sslot->state!=scoreboard_slot::state_free) && (sslot->pid>0))
29 kill(sslot->pid,SIGTERM);
30 }
31 collect_dead_souls(true);
32 }
33
34 void process_manager::manage() {
35 while(!finishing) {
36 manage_children();
37 // XXX: is it the way it should be?
38 sleep(10);
39 wait_for_children();
40 }
41 collect_dead_souls(true);
42 }
43
44 void process_manager::collect_dead_souls(bool actively) {
45 for(int tries=5;(tries>0) && (sboard.count_slots(scoreboard_slot::state_free)!=MAX_SITECING_SCOREBOARD_SLOTS);tries--) {
46 if(actively) {
47 for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
48 scoreboard_slot *sslot = sboard.get_slot(tmp);
49 if((sslot->state!=scoreboard_slot::state_free) && (sslot->pid>0))
50 kill(sslot->pid,SIGTERM);
51 }
52 }
53 wait_for_children(false);
54 // XXX: again.. is it the right way?
55 sleep(1);
56 }
57 }
58
59 void process_manager::wait_for_children(bool hang) {
60 int status;
61 int o = WUNTRACED;
62 if(!hang)
63 o|=WNOHANG;
64 while(sboard.count_slots(scoreboard_slot::state_free)<MAX_SITECING_SCOREBOARD_SLOTS) {
65 pid_t pid = waitpid(-1,&status,o);
66 if(!pid)
67 return;
68 if(pid<0) {
69 if(errno==EINTR)
70 return;
71 throw konforka::exception(CODEPOINT,"failed to waitpid()");
72 }
73 assert(pid);
74 int slot = sboard.get_slot_by_pid(pid);
75 sboard.free_slot(slot);
76 if(hang)
77 return;
78 }
79 }
80
81 void process_manager::manage_children() {
82 if(!spawn_children())
83 kill_children();
84 else
85 sleep(1); // just to get some rest.
86 }
87
88 bool process_manager::spawn_children() {
89 int total_children = 0;
90 int idle_children = 0;
91 for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
92 switch(sboard.get_slot(tmp)->state) {
93 case scoreboard_slot::state_free:
94 break;
95 case scoreboard_slot::state_idle:
96 idle_children++;
97 default:
98 total_children++;
99 break;
100 }
101 }
102 int total_lack = 0;
103 if(total_children<min_children)
104 total_lack = min_children-total_children;
105 int idle_lack = 0;
106 if(idle_children<min_spare_children)
107 idle_lack = min_spare_children-idle_children;
108 bool rv = false;
109 for(;(idle_lack>0 || total_lack>0) && (total_children<max_children);idle_lack--,total_lack--,total_children++) {
110 spawn_child();
111 rv = true;
112 }
113 return rv;
114 }
115
116 bool process_manager::kill_children() {
117 int idle_children = 0;
118 for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS;tmp++) {
119 if(sboard.get_slot(tmp)->state==scoreboard_slot::state_idle)
120 idle_children++;
121 }
122 int idle_excess = idle_children-max_spare_children;
123 bool rv = false;
124 for(int tmp=0;tmp<MAX_SITECING_SCOREBOARD_SLOTS && idle_excess>0;tmp++) {
125 scoreboard_slot *sslot = sboard.get_slot(tmp);
126 if((sslot->state==scoreboard_slot::state_idle) && (sslot->pid>0)) {
127 kill(sslot->pid,SIGTERM);
128 idle_excess--;
129 rv = true;
130 }
131 }
132 return rv;
133 }
134
135 void process_manager::spawn_child() {
136 int slot = sboard.allocate_slot();
137 pid_t pid = fork();
138 if(pid<0) {
139 sboard.free_slot(slot);
140 throw konforka::exception(CODEPOINT,"failed to fork()");
141 }
142 if(!pid) {
143 // child
144 sboard.get_slot(slot)->pid = getpid();
145 process(slot);
146 _exit(0);
147 }
148 // parent
149 sboard.get_slot(slot)->pid = pid;
150 }
151
152}