Return to BSD News archive
Path: sserve!newshost.anu.edu.au!harbinger.cc.monash.edu.au!msuinfo!agate!howland.reston.ans.net!cs.utexas.edu!uunet!zib-berlin.de!irz401!uriah!not-for-mail
From: j@uriah.sax.de (J Wunsch)
Newsgroups: comp.os.386bsd.bugs
Subject: Re: Bugs in Xboing 1.8
Date: 19 Aug 1994 19:23:48 +0200
Organization: Private U**X site; member IN e.V.
Lines: 530
Message-ID: <332pr4INN88q@bonnie.sax.de>
References: <32g8vl$6i6@ns.mcs.kent.edu>
NNTP-Posting-Host: bonnie.sax.de
borsburn@mcs.kent.edu (Bret Orsburn) writes:
Yet another item from the list of things i liked to have contributed
to FreeBSD 1.1.5, but didn't actually get the time to do it :-(
>1) When compiled with lockf file locking (the default), the program frequently
>hangs with ps indicating the process is waiting on WCHAN lockf. [...]
Yup, exactly every time you try to re-run it. The first run was always
okay. It succesfully locked the score file against itself ;-)
>A general observation: the audio architecture of xboing 1.8 seems pretty
>radical. There ought to be a way to make noises without forking and killing
>for every sound. [...]
Below is also my hack to get it work with FreeBSD's PCaudio driver.
Due to the overall slowness of it, i built my own version of an Xboing
audio driver. Instead of constantly forking and killing, i use a pipe
and start up a ``sound server''. The idea should be re-usable for real
audio devices, too.
>Meanwhile, I recommend xboing 1.8 (with audio enabled) to the FreeBSD
>development team as a kernel torture test: they probably never anticipated
>this rate of forking and killing!
You're wrong:-) John Dyson once posted his test program to the
hackers' list. If i remember well, it was something like quickly
forking some 5000 process off the parent...
Here's my patch to xboing:
*** highscore.c.dist Fri Aug 27 04:35:39 1993
--- highscore.c Sat Mar 26 14:20:26 1994
***************
*** 13,18 ****
--- 13,19 ----
#include <sys/param.h>
#include <sys/file.h>
#include <sys/types.h>
+ #include <sys/stat.h>
#include <netinet/in.h>
#include <pwd.h>
#include <X11/Xlib.h>
***************
*** 62,68 ****
static void SortHighScores(void);
static char *GetHomeDir(void);
static void DeleteScore(int index);
! static int LockUnlock(int cmd);
#else
static int LockUnlock();
static void DeleteScore();
--- 63,69 ----
static void SortHighScores(void);
static char *GetHomeDir(void);
static void DeleteScore(int index);
! static int LockUnlock(int cmd, int fd);
#else
static int LockUnlock();
static void DeleteScore();
***************
*** 738,746 ****
/* Lock the file for me only */
if (type == GLOBAL)
#ifdef USE_FLOCK
! id = LockUnlock(LOCK_EX);
#else
! id = LockUnlock(F_LOCK);
#endif
/* Read in the lastest scores */
--- 739,747 ----
/* Lock the file for me only */
if (type == GLOBAL)
#ifdef USE_FLOCK
! id = LockUnlock(LOCK_EX, -1);
#else
! id = LockUnlock(F_LOCK, -1);
#endif
/* Read in the lastest scores */
***************
*** 768,774 ****
else
{
/* Don't add as score is smaller */
! return False;
}
}
} /* for */
--- 769,775 ----
else
{
/* Don't add as score is smaller */
! goto doUnlock;
}
}
} /* for */
***************
*** 787,795 ****
/* Unlock the file now thanks */
if (id != -1)
#ifdef USE_FLOCK
! id = LockUnlock(LOCK_UN);
#else
! id = LockUnlock(F_ULOCK);
#endif
/* Yes - it was placed in the highscore */
--- 788,796 ----
/* Unlock the file now thanks */
if (id != -1)
#ifdef USE_FLOCK
! id = LockUnlock(LOCK_UN, id);
#else
! id = LockUnlock(F_ULOCK, id);
#endif
/* Yes - it was placed in the highscore */
***************
*** 797,808 ****
}
}
/* Unlock the file now thanks */
if (id != -1)
#ifdef USE_FLOCK
! id = LockUnlock(LOCK_UN);
#else
! id = LockUnlock(F_ULOCK);
#endif
/* Not even a highscore - loser! */
--- 798,810 ----
}
}
+ doUnlock:
/* Unlock the file now thanks */
if (id != -1)
#ifdef USE_FLOCK
! id = LockUnlock(LOCK_UN, id);
#else
! id = LockUnlock(F_ULOCK, id);
#endif
/* Not even a highscore - loser! */
***************
*** 1086,1095 ****
}
#if NeedFunctionPrototypes
! static int LockUnlock(int cmd)
#else
! static int LockUnlock(cmd)
! int cmd;
#endif
{
int inter = -1;
--- 1088,1097 ----
}
#if NeedFunctionPrototypes
! static int LockUnlock(int cmd, int fd)
#else
! static int LockUnlock(cmd, fd)
! int cmd, fd;
#endif
{
int inter = -1;
***************
*** 1103,1110 ****
strcpy(filename, HIGH_SCORE_FILE);
/* Open the highscore file for both read & write */
! if (cmd == F_LOCK || cmd == LOCK_EX)
inter = open(filename, O_RDWR);
/* Ok - if successful then lock or unlock the file */
if (inter != -1)
--- 1105,1121 ----
strcpy(filename, HIGH_SCORE_FILE);
/* Open the highscore file for both read & write */
! if (
! #ifndef USE_FLOCK
! cmd == F_LOCK
! #else
! cmd == LOCK_EX
! #endif
! )
inter = open(filename, O_RDWR);
+ else
+ /* use old fd to unlock */
+ inter = fd;
/* Ok - if successful then lock or unlock the file */
if (inter != -1)
***************
*** 1115,1121 ****
#endif
/* Are we unlocking the file */
! if (cmd == F_ULOCK || cmd == LOCK_UN)
{
/* Close the file now thanks */
close(inter);
--- 1126,1138 ----
#endif
/* Are we unlocking the file */
! if (
! #ifndef USE_FLOCK
! cmd == F_ULOCK
! #else
! cmd == LOCK_UN
! #endif
! )
{
/* Close the file now thanks */
close(inter);
*** /dev/null Mon Aug 15 21:33:00 1994
--- audio/BSDaudio.c Thu Apr 21 22:03:56 1994
***************
*** 0 ****
--- 1,299 ----
+ #include "include/copyright.h"
+
+ /* SUN Audio format - original code from play.c by Sun */
+ /*
+ * modified for Soeren Schmidt's pcaudio driver for (Free)BSD
+ * by Joerg Wunsch <joerg_wunsch@uriah.sax.de>
+ *
+ * Since pcaudio is a very slow device, a "sound daemon" is forked
+ * off. It gets the filenames to play from its input pipe and does
+ * the dirty work then. Poor man's multi-threading:-)
+ */
+
+ /*
+ * Include file dependencies:
+ */
+
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <stddef.h>
+ #include <string.h>
+ #include <ctype.h>
+ #include <errno.h>
+ #include <unistd.h>
+ #include <sys/stat.h>
+ #include <sys/fcntl.h>
+ #include <sys/signal.h>
+
+ #include <machine/pcaudioio.h>
+ #include <machine/endian.h>
+
+ #include "include/error.h"
+ #include "include/audio.h"
+
+ /*
+ * Internal macro definitions:
+ */
+
+ #define BUFFER_SIZE (1024 * SBUF_SIZE)
+
+ /*
+ * Internal type declarations:
+ */
+
+ #if NeedFunctionPrototypes
+ static void sigalarm_handler(int);
+ #else
+ static void sigalarm_handler();
+ #endif
+
+ /*
+ * Internal variable declarations:
+ */
+
+
+ unsigned char buf[BUFFER_SIZE]; /* size should depend on sample_rate */
+ char *Audio_dev = "/dev/pcaudio";
+ int Audio_fd = -1; /* file descriptor for audio device */
+ int err;
+ struct stat st;
+ int cnt;
+ char errorString[255];
+ static pid_t daemonpid = (pid_t) -2;
+ static int piped[2];
+
+ #if NeedFunctionPrototypes
+ int SetUpAudioSystem(Display *display)
+ #else
+ int SetUpAudioSystem(display)
+ Display *display;
+ #endif
+ {
+ /* Validate and open the audio device */
+ if (stat(Audio_dev, &st) < 0)
+ {
+ /* No audio device so barf */
+ sprintf(errorString, "Cannot stat audio device %s.", Audio_dev);
+ ErrorMessage(errorString);
+ return False;
+ }
+
+ /* Check that the audio device is a character device */
+ if (!S_ISCHR(st.st_mode))
+ {
+ /* Not a character device which is not right */
+ sprintf(errorString, "%s is not an audio device.", Audio_dev);
+ ErrorMessage(errorString);
+ return False;
+ }
+
+ /*
+ * We open the device without the O_NDELAY flag so that someone else
+ * who has the device can release it to us. If we use the O_NDELAY
+ * flag, the open will fail even if the process that has the device is
+ * willing to release it. Unfortunately, an ill-behaved process may not
+ * be willing to give up the device. In this case, the open will hang.
+ * To prevent this, we wrap an alarm around the open. If the open hangs
+ * and the alarm goes off, the open will return with errno = EINTR.
+ * suggestion by: jra@hrcms.jazz.att.com (Jeffry R. Abramson)
+ */
+ if ((int)signal(SIGALRM, sigalarm_handler) < 0)
+ {
+ ErrorMessage("signal(SIGALRM) failed.");
+ return False;
+ }
+
+ alarm(2);
+ /* Try to open audio device */
+ Audio_fd = open(Audio_dev, O_WRONLY);
+ alarm(0);
+
+ if ((Audio_fd < 0) && (errno == EBUSY || errno == EINTR))
+ {
+ /* The audio is in use so barf */
+ sprintf(errorString, "%s audio device is busy.", Audio_dev);
+ ErrorMessage(errorString);
+ return False;
+ }
+
+ /* Ok so we cannot open it for some reason */
+ if (Audio_fd < 0)
+ {
+ sprintf(errorString, "Cannot open audio device %s.", Audio_dev);
+ ErrorMessage(errorString);
+ return False;
+ }
+
+ if(daemonpid == (pid_t) -2 && pipe(piped) < 0)
+ {
+ ErrorMessage("Unable to create sound daemon pipe");
+ return False;
+ }
+
+ /* if the daemon is not yet running, start it */
+ if(daemonpid == (pid_t) -2)
+ {
+ daemonpid = fork();
+ if(daemonpid > 0)
+ (void) close(piped[0]);
+ }
+
+ if(daemonpid == (pid_t) -1)
+ {
+ /* cannot fork barf */
+ ErrorMessage("Cannot fork off sound daemon");
+ return False;
+ }
+
+ if(daemonpid == 0)
+ {
+ /* the child: our sound daemon */
+ FILE *pipefile;
+
+ close(piped[1]);
+ if((pipefile = fdopen(piped[0], "r")) == NULL)
+ {
+ ErrorMessage("Cannot make pipe buffer");
+ exit(1);
+ }
+
+ for(;;)
+ {
+ char soundfile[1024];
+ char *cp;
+ int ifd;
+ struct {
+ char magic[4]; /* magic string ".snd" */
+ long hdr_len; /* header length, in network byte order */
+ } filehdr;
+
+ /*
+ * the pipe is our semaphore; this read will block until
+ * the parent gives us a filename to play
+ */
+ if(fgets(soundfile, 1024, pipefile) == NULL)
+ {
+ /* our input pipe has been closed thanks */
+ close(Audio_fd);
+ exit(0);
+ }
+
+ if((cp = strchr(soundfile, '\n')) != 0)
+ *cp = 0;
+
+ /* Open the sound file for reading */
+ if ((ifd = open(soundfile, O_RDONLY, 0)) < 0)
+ {
+ /* Issue an error about not opening sound file */
+ sprintf(errorString, "Unable to open sound file %s.", soundfile);
+ WarningMessage(errorString);
+ break; /* back to outer loop */
+ }
+
+ /* validate the header */
+ read(ifd, (char *)&filehdr, sizeof(filehdr));
+ if(strncmp(filehdr.magic, ".snd", 4))
+ {
+ sprintf(errorString, "%s does not appear to be a soundfile",
+ soundfile);
+ WarningMessage(errorString);
+ break;
+ }
+ (void) lseek(ifd, SEEK_SET, ntohl(filehdr.hdr_len));
+
+ /* At this point, we're all ready to copy the data. */
+ while ((cnt = read(ifd, (char *) buf, BUFFER_SIZE)) >= 0)
+ {
+ /* If input EOF, write an eof marker */
+ err = write(Audio_fd, (char *)buf, cnt);
+ if (err != cnt)
+ {
+ /* Did we succeed in writing all the sound out */
+ sprintf(errorString,
+ "Problem while writing to audio device.");
+ WarningMessage(errorString);
+ break;
+ }
+
+ if (cnt == 0) break;
+ }
+
+ if (cnt < 0)
+ {
+ /* Some error - while reading - notify user */
+ sprintf(errorString, "Problem while reading soundfile %s", soundfile);
+ WarningMessage(errorString);
+ }
+
+ /* Close the sound file */
+ (void) close(ifd);
+ }
+ }
+
+ /* Success in opening audio device */
+ return True;
+ }
+
+ #if NeedFunctionPrototypes
+ void FreeAudioSystem(void)
+ #else
+ void FreeAudioSystem()
+ #endif
+ {
+ /* Close the audio device thanks */
+ (void) close(Audio_fd);
+ (void) close(piped[1]); /* this will shut down the daemon */
+ daemonpid = (pid_t) -2;
+ }
+
+ #if NeedFunctionPrototypes
+ void SetMaximumVolume(int Volume)
+ #else
+ void SetMaximumVolume(Volume)
+ int Volume;
+ #endif
+ {
+ /* Set the maximum volume for the audio system */
+ }
+
+ #if NeedFunctionPrototypes
+ void playSoundFile(char *filename, int volume)
+ #else
+ void playSoundFile(filename, volume)
+ char *filename;
+ int volume;
+ #endif
+ {
+ char soundfile[1024];
+ char *str;
+
+ /* Construct the sounds file path and use env var if exists */
+ if ((str = getenv("XBOING_SOUND_DIR")) != NULL)
+ sprintf(soundfile, "%s/%s.au\n", str, filename);
+ else
+ sprintf(soundfile, "%s/%s.au\n", SOUNDS_DIR, filename);
+
+ /* give the daemon its file name to operate on */
+ write(piped[1], soundfile, strlen(soundfile));
+ }
+
+ #if NeedFunctionPrototypes
+ void audioDeviceEvents(void)
+ #else
+ void audioDeviceEvents()
+ #endif
+ {
+ /* None to do */
+ }
+
+ /* ARGSUSED */
+ #if NeedFunctionPrototypes
+ static void sigalarm_handler(int signo)
+ #else
+ static void sigalarm_handler(signo)
+ int signo;
+ #endif
+ {
+ /* Used to fix problem when opening the audio device */
+ return;
+ }
--
cheers, J"org work: joerg_wunsch@tcd-dresden.de
private: joerg_wunsch@uriah.sax.de
Steinbach's Guideline for Systems Programming:
Never test for an error condition you don't know how to handle.