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.