]> git.donarmstrong.com Git - infobot.git/blob - blootbot/src/Shm.pl
- forker (POSIX::_exit) fixes.
[infobot.git] / blootbot / src / Shm.pl
1 #
2 #   Shm.pl: Shared Memory stuff.
3 #    Author: dms
4 #   Version: 20000201
5 #   Created: 20000124
6 #
7
8 if (&IsParam("useStrict")) { use strict; }
9
10 use POSIX qw(_exit);
11
12 sub openSHM {
13     my $IPC_PRIVATE = 0;
14     my $size = 2000;
15
16     if (defined( $_ = shmget($IPC_PRIVATE, $size, 0777) )) {
17         &status("Created shared memory (shm) key: [$_]");
18         return $_;
19     } else {
20         &ERROR("openSHM: failed.");
21         &ERROR("Please delete some shared memory with ipcs or ipcrm.");
22         exit 1;
23     }
24 }
25
26 sub closeSHM {
27     my ($key) = @_;
28     my $IPC_RMID = 0;
29
30     return '' if (!defined $key);
31
32     &shmFlush();
33     &status("Closed shared memory (shm) key: [$key]");
34     return shmctl($key, $IPC_RMID, 0);
35 }
36
37 sub shmRead {
38     my ($key) = @_;
39     my $position = 0;
40     my $size = 3*80;
41     my $retval = '';
42
43     if (shmread($key,$retval,$position,$size)) {
44         return $retval;
45     } else {
46         &ERROR("shmRead: failed: $!");
47         return '';
48     }
49 }
50
51 sub shmWrite {
52     my ($key, $str) = @_;
53     my $position = 0;
54     my $size = 80*3;
55
56     # NULL hack.
57     ### TODO: create shmClear to deal with this.
58     if ($str !~ /^$/) {
59         my $read = &shmRead($key);
60         $read =~ s/\0+//g;
61         $str = $read ."||". $str if ($read ne "");
62     }
63
64     if (!shmwrite($key,$str,$position,$size)) {
65         &ERROR("shmWrite: failed: $!");
66     }
67 }
68
69 ##############
70 ### Helpers
71 ###
72
73 # Usage: &addForked($name);
74 # Return: 1 for success, 0 for failure.
75 sub addForked {
76     my ($name)          = @_;
77     my $forker_timeout  = 360;  # 6mins, in seconds.
78     $forker             = $name;
79
80     if (!defined $name) {
81         &WARN("addForked: name == NULL.");
82         return 0;
83     }
84
85     foreach (keys %forked) {
86         my $time = time() - $forked{$_}{Time};
87         next unless ($time > $forker_timeout);
88
89         ### TODO: use &time2string()?
90         &WARN("Fork: looks like we lost '$_', executed $time ago.");
91         delete $forked{$_};
92     }
93
94     my $count = 0;
95     while (scalar keys %forked > 2) {   # 2 or more == fail.
96         sleep 1;
97
98         if ($count > 3) {       # 3 seconds.
99             my $list = join(', ', keys %forked);
100             if (defined $who) {
101                 &msg($who, "already running ($list) => exceeded allowed forked processes count (1?).");
102             } else {
103                 &status("Fork: I ran too many forked processes :) Giving up $name.");
104             }
105             return 0;
106         }
107
108         $count++;
109     }
110
111     if (exists $forked{$name}) {
112         my $time = $forked{$name}{Time};
113         if (-d "/proc/$forked{$name}{PID}") {
114             &status("fork: still running; good. BAIL OUT.");
115         } else {
116             &status("fork: lost the fork? REMOVE IT!");
117         }
118
119         if (time() - $time > 900) {     # stale fork > 15m.
120             &status("forked: forked{$name} presumably exited without notifying us.");
121             $forked{$name}{Time} = time();
122             return 1;
123         } else {                                # fresh fork.
124             &msg($who, "$name is already running ". &Time2String(time() - $forked{$name}));
125             return 0;
126         }
127     } else {
128         $forked{$name}{Time}    = time();
129         $forkedtime             = time();
130         $count{'Fork'}++;
131         return 1;
132     }
133 }
134
135 sub delForked {
136     my ($name)  = @_;
137
138     return if ($$ == $bot_pid);
139
140     if (!defined $name) {
141         &WARN("delForked: name == NULL.");
142         POSIX::_exit(0);
143     }
144
145     &showProc();        # just for informational purposes.
146
147     if (exists $forked{$name}) {
148         my $timestr = &Time2String(time() - $forked{$name}{Time});
149         &status("fork: took $timestr for $name.");
150         &shmWrite($shm,"DELETE FORK $name");
151     } else {
152         &ERROR("delForked: forked{$name} does not exist. should not happen.");
153     }
154
155     &status("fork finished for '$name'.");
156
157     POSIX::_exit(0);
158 }
159
160 1;