2 # Shm.pl: Shared Memory stuff.
14 if (&IsParam("noSHM")) {
15 &status("Created shared memory: disabled. [bot may become unreliable]");
19 if (defined( $_ = shmget($IPC_PRIVATE, $size, 0777) )) {
20 &status("Created shared memory (shm) key: [$_]");
23 &ERROR("openSHM: failed.");
24 &ERROR("Please delete some shared memory with ipcs or ipcrm.");
33 return '' if (!defined $key);
36 &status("Closed shared memory (shm) key: [$key]");
37 return shmctl($key, $IPC_RMID, 0);
46 return '' if (&IsParam("noSHM"));
48 if (shmread($key,$retval,$position,$size)) {
51 &ERROR("shmRead: failed: $!");
52 ### TODO: if this fails, never try again.
63 return if (&IsParam("noSHM"));
66 ### TODO: create shmClear to deal with this.
68 my $read = &shmRead($key);
72 $str = time().": "; # time stamping, null.
73 } elsif ($read eq "") {
74 $str = time().": "; # timestamping.
76 $str = $read ."||". $str;
80 if (!shmwrite($key,$str,$position,$size)) {
81 &ERROR("shmWrite: failed: $!");
89 # Usage: &addForked($name);
90 # Return: 1 for success, 0 for failure.
93 my $forker_timeout = 360; # 6mins, in seconds.
97 &WARN("addForked: name == NULL.");
101 foreach (keys %forked) {
103 my $time = time() - $forked{$n}{Time};
104 next unless ($time > $forker_timeout);
106 ### TODO: use &time2string()?
107 &WARN("Fork: looks like we lost '$n', executed $time ago");
109 my $pid = $forked{$n}{PID};
111 &WARN("Fork: no pid for $n.");
118 &status("Fork: pid == \$\$ ($$)");
122 if ( -d "/proc/$pid") {
123 &status("Fork: killing $name ($pid)");
131 while (scalar keys %forked > 1) { # 2 or more == fail.
134 if ($count > 3) { # 3 seconds.
135 my $list = join(', ', keys %forked);
137 &msg($who, "already running ($list) => exceeded allowed forked processes count (1?).");
139 &status("Fork: I ran too many forked processes :) Giving up $name.");
147 if (exists $forked{$name} and !scalar keys %{ $forked{$name} }) {
148 &WARN("addF: forked{$name} exists but is empty; deleting.");
149 undef $forked{$name};
152 if (exists $forked{$name} and scalar keys %{ $forked{$name} }) {
153 my $time = $forked{$name}{Time};
156 $continue++ if ($forked{$name}{PID} == $$);
159 &WARN("hrm.. fork pid == mypid == $$; how did this happen?");
161 } elsif ( -d "/proc/$forked{$name}{PID}") {
162 &status("fork: still running; good. BAIL OUT.");
166 &WARN("Found dead fork; removing and resetting.");
173 } elsif (time() - $time > 900) { # stale fork > 15m.
174 &status("forked: forked{$name} presumably exited without notifying us.");
176 } else { # fresh fork.
177 &msg($who, "$name is already running ". &Time2String(time() - $time));
182 $forked{$name}{Time} = time();
183 $forked{$name}{PID} = $$;
184 $forkedtime = time();
192 return if ($$ == $bot_pid);
194 if (!defined $name) {
195 &WARN("delForked: name == NULL.");
199 if ($name =~ /\.pl/) {
200 &WARN("dF: name is name of source file ($name). FIX IT!");
203 &showProc(); # just for informational purposes.
205 if (exists $forked{$name}) {
206 my $timestr = &Time2String(time() - $forked{$name}{Time});
207 &status("fork: took $timestr for $name.");
208 &shmWrite($shm,"DELETE FORK $name");
210 &ERROR("delForked: forked{$name} does not exist. should not happen.");
213 &status("--- fork finished for '$name' ---");
219 return if ($$ != $::bot_pid); # fork protection.
222 &ScheduleThis(5, "shmFlush");
223 return if ($_[0] eq "2");
227 my $shmmsg = &shmRead($shm);
228 $shmmsg =~ s/\0//g; # remove padded \0's.
229 if ($shmmsg =~ s/^(\d+): //) {
233 foreach (split '\|\|', $shmmsg) {
235 &VERB("shm: Processing '$_'.",2);
237 if (/^DCC SEND (\S+) (\S+)$/) {
238 my ($nick,$file) = ($1,$2);
239 if (exists $dcc{'SEND'}{$who}) {
240 &msg($nick, "DCC already active.");
242 &DEBUG("shm: dcc sending $2 to $1.");
243 $conn->new_send($1,$2);
244 $dcc{'SEND'}{$who} = time();
246 } elsif (/^SET FORKPID (\S+) (\S+)/) {
247 $forked{$1}{PID} = $2;
248 } elsif (/^DELETE FORK (\S+)$/) {
250 } elsif (/^EVAL (.*)$/) {
251 &DEBUG("evaling '$1'.");
254 &DEBUG("shm: unknown msg. ($_)");
258 &shmWrite($shm,"") if ($shmmsg ne "");