CGI-SpeedyCGI

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

	- 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

    </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

================
- 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

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

 *
 */

/* 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

	    );
	    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

	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

	    );
	    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

	/* 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

    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


#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


	/* 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

 * 
 * 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

	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

 */

#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

    {
	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

    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

	    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

    } 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 1.061 second using v1.01-cache-2.11-cpan-49f99fa48dc )