CGI-SpeedyCGI

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
        - Fix from Lars Thegler for buffer overrun in speedy_opt.c
 
        - Add efence malloc debugging.
 
2.21    Thu Sep 26 15:27:35 PDT 2002
 
        - Fix too many backends problem reported by Theo Petersen.  The
          problem is due to temp-file corruption that occurs when the
          web-server sends a TERM signal to the frontend while it is working
          on the temp file.  It also results in some backends failing due
          to the corruption.  Added a fix so that signals are always blocked
          while working on the temp file.
 
        - Shutdown handler should be called after script is touched.
 
        - Fixes for Mac OS X 10.1.  Workaround the sigpending() bug,
          and add msync() which appears to fix a shared-memory flushing
          problem when temp-file is expanded.
 
2.20    Wed Sep 11 19:33:36 PDT 2002

docs/file_struct.html  view on Meta::CPAN

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
    </td>
    <td>
        Number of slots in the slot array.
    </td>
</tr>
<tr>
    <td>
        file_corrupt
    </td>
    <td>
        Boolean - is this file corrupt?  This is true if a process locked
        this file, but exited or was killed before unlocking it.
    </td>
</tr>
<tr>
    <td>
        file_removed
    </td>
    <td>
        Boolean - has this file been removed from the filesystem?
    </td>

docs/prog_outline.txt  view on Meta::CPAN

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
================
- While no connection:
    - Stat our script file
    - Call "Get a Backend"
    - If we got a backend:
        - Try to connect
        - If connection successful, return
        - If connection failed:
            - Unless there's a bug in the code somewhere, this BE must've
              been killed and not yet cleaned up.  Since we've already
              unlocked the file, if we try to go do a cleanup, we may get
              there after another process does.  So, we may be overwriting
              some other unrelated slot data instead.  This could be
              solved with some data in the BE slot where we allocate
              this BE to our pid before unlocking, making us the only pid
              allowed to clean it up.  Or we could go back and track down our
              group/script again and find this BE on the group's list,
              if it's still there.  But, both of these options are a lot
              of trouble for what should be a rare occurance anyways -
              if the process is dead, the normal cleanup mechanism should
              eventually get rid of it anyways (assuming no PID wrap).

docs/prog_outline.txt  view on Meta::CPAN

172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
Frontend Dispose
================
- ???
 
 
File Operations
---------------
 
File Lock
=========
- If file is already locked, return.
- If file-descriptor is marked suspect:
    - If file is open:
        - Fstat the open file-descriptor
        - If fstat fails or different dev/inode:
            - "Unmap the file"
            - Forget this file-descriptor
        - Endif
    - Endif
    - Mark file-descriptor OK
- Endif

src/speedy_file.c  view on Meta::CPAN

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
*
 */
 
/* Open/create, mmap and lock the speedy temp file */
 
#include "speedy.h"
 
speedy_file_t           *speedy_file_maddr;
static int              file_fd = -1;
static int              maplen;
static int              file_locked;
static char             *file_name, *saved_tmpbase;
static struct stat      file_stat;
static int              cur_state;
static time_t           last_reopen;
#ifdef SPEEDY_BACKEND
static int              fd_is_suspect;
#endif
 
#define fillin_fl(fl)           \
    fl.l_whence = SEEK_SET;     \

src/speedy_file.c  view on Meta::CPAN

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
            );
            if (speedy_file_maddr == (speedy_file_t*)MAP_FAILED)
                speedy_util_die("mmap failed");
        }
    }
}
 
static void file_unlock(void) {
    struct flock fl;
 
    if (!file_locked)
        return;
 
    FILE_HEAD.lock_owner = 0;
 
    fillin_fl(fl);
    fl.l_type = F_UNLCK;
    if (fcntl(file_fd, F_SETLK, &fl) == -1) speedy_util_die("unlock file");
    file_locked = 0;
 
    speedy_sig_blockall_undo();
}
 
/* Only call this if you're sure the fd is not suspect */
static void file_close2(void) {
 
#ifdef SPEEDY_BACKEND
    if (fd_is_suspect)
        DIE_QUIET("file_close2: assertion failed - fd_is_suspect");

src/speedy_file.c  view on Meta::CPAN

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
        speedy_free(*ptr);
    *ptr = newval;
}
 
static void file_lock(void) {
    static struct timeval file_create_time;
    struct flock fl;
    int tries;
    time_t now;
 
    if (file_locked)
        return;
 
#ifdef SPEEDY_BACKEND
    fix_suspect_fd();
#endif
 
    /* Re-open the temp file occasionally or if tmpbase changed */
    if ((now = speedy_util_time()) - last_reopen > OPTVAL_RESTATTIMEOUT ||
        !saved_tmpbase || strcmp(saved_tmpbase, OPTVAL_TMPBASE) != 0)
    {

src/speedy_file.c  view on Meta::CPAN

193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
    );
    if (file_fd == -1) speedy_util_die("open temp file");
    fcntl(file_fd, F_SETFD, FD_CLOEXEC);
}
 
/* Lock the file */
fillin_fl(fl);
fl.l_type = F_WRLCK;
if (fcntl(file_fd, F_SETLKW, &fl) == -1) speedy_util_die("lock file");
 
/* Fstat the file, now that it's locked down */
get_stat();
 
/* Map into memory */
file_map(file_stat.st_size);
 
/* If file is too small (0 or below MIN_SLOTS_FREE), extend it */
if (file_stat.st_size < sizeof(file_head_t) ||
    file_stat.st_size < sizeof(file_head_t) +
        sizeof(slot_t) * (FILE_HEAD.slots_alloced + MIN_SLOTS_FREE))
{

src/speedy_file.c  view on Meta::CPAN

239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
        /* If file has not been removed then all done */
        if (!FILE_HEAD.file_removed)
            break;
 
        /* File is invalid */
        if (cur_state >= FS_HAVESLOTS) {
            /* Too late for this proc - slotnums have changed, can't recover */
            DIE_QUIET("temp file is corrupt");
        } else {
            /* Bad luck - the file was unlinked after we opened it (possibly
             * by us because it was corrupt), but before we locked it.
             * Try again.
             */
            file_close2();
        }
    }
    if (!tries) {
        DIE_QUIET("could not open temp file");
    }
 
    /* Block all sigs while writing to file */
    speedy_sig_blockall();
    file_locked = 1;
    FILE_HEAD.lock_owner = speedy_util_getpid();
}
 
static void file_close(void) {
    /* If no groups left, remove the file */
    if (cur_state >= FS_HAVESLOTS) {
        file_lock();
        if (!FILE_HEAD.group_head && !FILE_HEAD.fe_run_head)
            remove_file(0);
    }

src/speedy_file.c  view on Meta::CPAN

297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
    int retval = cur_state;
 
    if (new_state != cur_state) {
        switch_state(new_state);
        cur_state = new_state;
    }
    return retval;
}
 
void speedy_file_fork_child(void) {
    if (file_locked)
        speedy_sig_blockall_undo();
    file_locked = 0;
    if (cur_state > FS_HAVESLOTS)
        speedy_file_set_state(FS_HAVESLOTS);
}
 
#ifdef SPEEDY_BACKEND
void speedy_file_need_reopen(void) {
    last_reopen = 0;
}
#endif

src/speedy_file.h  view on Meta::CPAN

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#define FILE_ALLOC_CHUNK        512
#define FILE_REV                6
#define FILE_HEAD               (speedy_file_maddr->file_head)
#define FILE_SLOTS              (speedy_file_maddr->slots)
#define FILE_SLOT(member, n)    (FILE_SLOTS[SLOT_CHECK(n)-1].slot_u.member)
#define MIN_SLOTS_FREE          5
 
/* File access states */
#define FS_CLOSED       0       /* File is closed, not mapped */
#define FS_OPEN         1       /* Unlocked.  Keep open for performance only */
#define FS_HAVESLOTS    2       /* Unlocked.  We are holding onto slots in
                                   this file */
#define FS_CORRUPT      3       /* Locked, mmaped, non-atomic writes to file */
 
extern speedy_file_t *speedy_file_maddr;
SPEEDY_INLINE void speedy_file_fd_is_suspect(void);
int speedy_file_size(void);
SPEEDY_INLINE int speedy_file_set_state(int new_state);
void speedy_file_need_reopen(void);
void speedy_file_fork_child(void);

src/speedy_frontend.c  view on Meta::CPAN

324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
    /* Unlock the file */
    speedy_file_set_state(FS_HAVESLOTS);
 
    /* Set an alarm for one-second or so. */
    alarm(OPTVAL_BECHECKTIMEOUT);
 
    /* Wait for a timeout or signal from backend */
    speedy_sig_wait(&sl);
 
    /* Find out if our file changed.  Do this while unlocked */
    file_changed = speedy_script_changed();
 
    /* Acquire lock.  If group bad or file changed, then done */
    if (!speedy_group_lock(gslotnum) || file_changed)
        break;
}
 
/* Remove our FE slot from the queue.  */
speedy_slot_remove(fslotnum,
    &(FILE_SLOT(gr_slot, gslotnum).fe_head),

src/speedy_group.h  view on Meta::CPAN

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
*
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */
 
void speedy_group_invalidate(slotnum_t gslotnum);
void speedy_group_sendsigs(slotnum_t gslotnum);
void speedy_group_cleanup(slotnum_t gslotnum);
int speedy_group_connect_locked(slotnum_t gslotnum);
slotnum_t speedy_group_create(void);
pid_t speedy_group_be_starting(slotnum_t gslotnum);
int speedy_group_parent_sig(slotnum_t gslotnum, int sig);
int speedy_group_start_be(slotnum_t gslotnum);
int speedy_group_lock(slotnum_t gslotnum);
 
#define speedy_group_name_match(gslotnum) \
    (FILE_SLOT(gr_slot, (gslotnum)).name_slot && \
    !strncmp(FILE_SLOT(grnm_slot, FILE_SLOT(gr_slot, (gslotnum)).name_slot).name, OPTVAL_GROUP, GR_NAMELEN))

src/speedy_perl.c  view on Meta::CPAN

406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
        perl_destruct(my_perl);
    }
    speedy_util_exit(0,0);
}
 
/* Wait for a connection from a frontend */
static void backend_accept(void) {
    SigList sl;
    int ok;
 
    /* Set up caught/unblocked signals to exit on */
    speedy_sig_init(&sl, caught_sigs, NUMSIGS, SIG_UNBLOCK);
 
    /* Wait for an accept or timeout */
    ok = speedy_ipc_accept(OPTVAL_TIMEOUT*1000);
 
    /* Put signals back to original settings */
    speedy_sig_free(&sl);
 
    /* If timed out or signal, then finish up */
    if (!ok)

src/speedy_sig.c  view on Meta::CPAN

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
*/
 
#include "speedy.h"
 
/*
 * Signal handling routines
 */
 
static volatile int got_sig[SPEEDY_MAXSIG];
static sigset_t blockall_save;
static int all_blocked;
 
void speedy_sig_blockall(void) {
    sigset_t full_set;
 
    sigfillset(&full_set);
    sigprocmask(SIG_BLOCK, &full_set, &blockall_save);
    all_blocked = 1;
}
 
void speedy_sig_blockall_undo(void) {
    sigprocmask(SIG_SETMASK, &blockall_save, NULL);
    all_blocked = 0;
}
 
static int sig_find(const volatile int sig_rcvd[SPEEDY_MAXSIG], int sig) {
    register int i;
 
    for (i = 0; i < SPEEDY_MAXSIG && sig_rcvd[i]; ++i) {
        if (sig_rcvd[i] == sig)
            return -1;
    }
    return i;

src/speedy_sig.c  view on Meta::CPAN

82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
{
    struct sigaction sigact;
    sigact.sa_handler = &sig_handler;
    sigact.sa_flags = 0;
    sigemptyset(&sigact.sa_mask);
    for (i = 0; i < sl->numsigs; ++i)
        sigaction(sl->signum[i],  &sigact, &(sl->sigact_save[i]));
}
 
/* Block or unblock our signals.  Save original mask */
if (all_blocked) {
    sl->sigset_save = blockall_save;
    for (i = 0; i < sl->numsigs; ++i) {
        if (how == SIG_BLOCK)
            sigaddset(&blockall_save, sl->signum[i]);
        else
            sigdelset(&blockall_save, sl->signum[i]);
    }
} else {
    sigset_t block_sigs;
    sigemptyset(&block_sigs);

src/speedy_sig.c  view on Meta::CPAN

120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
    sl->numsigs = numsigs;
 
    /* Finish init */
    sig_init2(sl, how);
}
 
void speedy_sig_free(const SigList *sl) {
    int i;
     
    /* Get rid of any pending signals.  On Sun/apache-2 we don't get pending
     * signals as soon as they are unblocked - instead they get delivered
     * after the action is restored, which is not what we want.
     */
    do {
        sigset_t set;
         
        /* Bug in Mac OS X 10.1 and earlier - sigpending is essentially a
         * no-op, so we get garbage, and get stuck in sigsuspend.
         * Workaround by clearing out the set initially so we get no pending
         * signals back.
         */

src/speedy_sig.c  view on Meta::CPAN

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
            break;
        for (i = 0; i < sl->numsigs; ++i) {
            if (sigismember(&set, sl->signum[i])) {
                sig_wait_basic(sl);
                break;
            }
        }
    } while (i < sl->numsigs);
 
    /* Unblock sigs */
    if (all_blocked)
        blockall_save = sl->sigset_save;
    else
        sigprocmask(SIG_SETMASK, &sl->sigset_save, NULL);
 
    /* Install old handlers */
    for (i = 0; i < sl->numsigs; ++i)
        sigaction(sl->signum[i], &(sl->sigact_save[i]), NULL);
}

src/speedy_slot.c  view on Meta::CPAN

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
} else {
    /* Allocate a new slot */
    slotnum = FILE_HEAD.slots_alloced + 1;
 
    /* Abort if too many slots */
    if (slotnum >= MAX_SLOTS)
        DIE_QUIET("Out of slots");
 
    /* Check here if the file is large enough to hold this slot.
     * The speedy_file code is supposed to allocate enough extra
     * slots (MIN_SLOTS_FREE) when the file is locked to satisfy
     * all slot_alloc's until the file is unlocked.  But if the
     * code starts allocating too many slots for whatever reason,
     * that will not work, and we'll drop off the end of the file.
     * In that case, either fix the code or bump MIN_SLOTS_FREE
     */
    if (sizeof(file_head_t)+slotnum*sizeof(slot_t) > speedy_file_size()) {
        speedy_util_die(
            "File too small for another slot while allocating slotnum %d. File size=%d. Try increasing MIN_SLOTS_FREE.",
            slotnum, speedy_file_size()
        );
    }



( run in 0.333 second using v1.01-cache-2.11-cpan-e5176c747c2 )