]> git.donarmstrong.com Git - infobot.git/blob - src/Shm.pl
- added weather from Nathan Moschkin <logeist@guinerd.myip.org>. Thanks!
[infobot.git] / src / Shm.pl
1 #
2 #   Shm.pl: Shared Memory stuff.
3 #    Author: dms
4 #   Version: 20000201
5 #   Created: 20000124
6 #
7
8 #use strict;
9 use POSIX qw(_exit);
10
11 sub openSHM {
12     my $IPC_PRIVATE = 0;
13     my $size = 2000;
14
15     if (&IsParam("noSHM")) {
16         &status("Created shared memory: disabled. [bot may become  unreliable]");
17         return 0;
18     }
19
20     if (defined( $_ = shmget($IPC_PRIVATE, $size, 0777) )) {
21         &status("Created shared memory (shm) key: [$_]");
22         return $_;
23     } else {
24         &ERROR("openSHM: failed.");
25         &ERROR("Please delete some shared memory with ipcs or ipcrm.");
26         exit 1;
27     }
28 }
29
30 sub closeSHM {
31     my ($key) = @_;
32     my $IPC_RMID = 0;
33
34     return '' if (!defined $key);
35
36     &shmFlush();
37     &status("Closed shared memory (shm) key: [$key]");
38     return shmctl($key, $IPC_RMID, 0);
39 }
40
41 sub shmRead {
42     my ($key) = @_;
43     my $position = 0;
44     my $size = 3*80;
45     my $retval = '';
46
47     return '' if (&IsParam("noSHM"));
48
49     if (shmread($key,$retval,$position,$size)) {
50         return $retval;
51     } else {
52         &ERROR("shmRead: failed: $!");
53         ### TODO: if this fails, never try again.
54         &openSHM();
55         return '';
56     }
57 }
58
59 sub shmWrite {
60     my ($key, $str) = @_;
61     my $position = 0;
62     my $size = 80*3;
63
64     return if (&IsParam("noSHM"));
65
66     # NULL hack.
67     ### TODO: create shmClear to deal with this.
68     if ($str !~ /^$/) {
69         my $read = &shmRead($key);
70         $read =~ s/\0+//g;
71
72         if ($str eq "") {
73             $str = time().": ";         # time stamping, null.
74         } elsif ($read eq "") {
75             $str = time().": ";         # timestamping.
76         } else {
77             $str = $read ."||". $str;
78         }
79     }
80
81     if (!shmwrite($key,$str,$position,$size)) {
82         &ERROR("shmWrite: failed: $!");
83     }
84 }
85
86 ##############
87 ### Helpers
88 ###
89
90 # Usage: &addForked($name);
91 # Return: 1 for success, 0 for failure.
92 sub addForked {
93     my ($name)          = @_;
94     my $forker_timeout  = 360;  # 6mins, in seconds.
95     $forker             = $name;
96
97     if (!defined $name) {
98         &WARN("addForked: name == NULL.");
99         return 0;
100     }
101
102     foreach (keys %forked) {
103         my $n = $_;
104         my $time = time() - $forked{$n}{Time};
105         next unless ($time > $forker_timeout);
106
107         ### TODO: use &time2string()?
108         &WARN("Fork: looks like we lost '$n', executed $time ago");
109
110         my $pid = $forked{$n}{PID};
111         if (!defined $pid) {
112             &WARN("Fork: no pid for $n.");
113             delete $forked{$n};
114             next;
115         }
116
117         # don't kill parent!
118         if ($pid == $$) {
119             &status("Fork: pid == \$\$ ($$)");
120             next;
121         }
122
123         if ( -d "/proc/$pid") {
124             &status("Fork: killing $name ($pid)");
125             kill 9, $pid;
126         }
127
128         delete $forked{$n};
129     }
130
131     my $count = 0;
132     while (scalar keys %forked > 1) {   # 2 or more == fail.
133         sleep 1;
134
135         if ($count > 3) {       # 3 seconds.
136             my $list = join(', ', keys %forked);
137             if (defined $who) {
138                 &msg($who, "already running ($list) => exceeded allowed forked processes count (1?).");
139             } else {
140                 &status("Fork: I ran too many forked processes :) Giving up $name.");
141             }
142             return 0;
143         }
144
145         $count++;
146     }
147
148     if (exists $forked{$name} and !scalar keys %{ $forked{$name} }) {
149         &WARN("addF: forked{$name} exists but is empty; deleting.");
150         undef $forked{$name};
151     }
152
153     if (exists $forked{$name} and scalar keys %{ $forked{$name} }) {
154         my $time        = $forked{$name}{Time};
155         my $continue    = 0;
156
157         $continue++ if ($forked{$name}{PID} == $$);
158
159         if ($continue) {
160             &WARN("hrm.. fork pid == mypid == $$; how did this happen?");
161
162         } elsif ( -d "/proc/$forked{$name}{PID}") {
163             &status("fork: still running; good. BAIL OUT.");
164             return 0;
165
166         } else {
167             &WARN("Found dead fork; removing and resetting.");
168             $continue = 1;
169         }
170
171         if ($continue) {
172             # NOTHING.
173
174         } elsif (time() - $time > 900) {        # stale fork > 15m.
175             &status("forked: forked{$name} presumably exited without notifying us.");
176
177         } else {                                # fresh fork.
178             &msg($who, "$name is already running ". &Time2String(time() - $time));
179             return 0;
180         }
181     }
182
183     $forked{$name}{Time}        = time();
184     $forked{$name}{PID}         = $$;
185     $forkedtime                 = time();
186     $count{'Fork'}++;
187     return 1;
188 }
189
190 sub delForked {
191     my ($name)  = @_;
192
193     return if ($$ == $bot_pid);
194
195     if (!defined $name) {
196         &WARN("delForked: name == NULL.");
197         POSIX::_exit(0);
198     }
199
200     if ($name =~ /\.pl/) {
201         &WARN("dF: name is name of source file ($name). FIX IT!");
202     }
203
204     &showProc();        # just for informational purposes.
205
206     if (exists $forked{$name}) {
207         my $timestr = &Time2String(time() - $forked{$name}{Time});
208         &status("fork: took $timestr for $name.");
209         &shmWrite($shm,"DELETE FORK $name");
210     } else {
211         &ERROR("delForked: forked{$name} does not exist. should not happen.");
212     }
213
214     &status("--- fork finished for '$name' ---");
215
216     POSIX::_exit(0);
217 }
218
219 1;