start_music creates a child process and replaces it with aplay.
The parent returns the child's PID so the caller can stop it later.
fork()
fork() duplicates the calling process. After fork() returns, two
processes are running: the parent and the child. They are identical
— same code, same memory, same file descriptors — up to one
difference: the return value.
| Return value | Who receives it |
|---|---|
0 | the child |
| child's PID (a positive integer) | the parent |
-1 | the caller, on error (no child was created) |
pid_t pid = fork();
if (pid == -1)
/* error — no child */
if (pid == 0)
/* this is the child */
/* this is the parent — pid holds the child's PID */The two processes diverge at the if chain. The child takes the
pid == 0 branch; the parent falls through.
exec()
Once the child is running, it holds a copy of the game's code and
memory. We do not want it to run the game — we want it to run aplay.
execlp replaces the current process image with a new program:
execlp("aplay", "aplay", "-q", path, NULL);The arguments:
"aplay"— the program name, found by searchingPATH"aplay"—argv[0]for the new process (by convention, the program's own name)"-q"— quiet mode: suppressesaplay's "Playing WAVE..." linepath— the WAV file to playNULL— terminates the argument list
If execlp succeeds, it does not return. The child process image
is gone; aplay is now running in its place. The game loop code in
the child ceases to exist.
If execlp fails (file not found, not executable), it returns -1
and the child is still alive. _exit(1) terminates it immediately.
_exit rather than exit because _exit does not flush stdio
buffers — flushing shared buffers in the child would corrupt the
parent's output.
start_music
#include "music.h"
pid_t start_music(const char *path)
{
pid_t pid;
pid = fork();
if (pid == -1)
return (-1);
if (pid == 0)
{
execlp("aplay", "aplay", "-q", path, NULL);
_exit(1);
}
return (pid);
}Replace the stub in music.c with this implementation.
What happens when you call it
pid_t music_pid = start_music("music/tier1.wav");fork()creates a child. Two processes now exist.- The child enters the
pid == 0branch and callsexeclp. - The child's process image is replaced by
aplay.aplaybegins readingmusic/tier1.wavand writing decoded audio to ALSA. - The parent receives the child's PID and returns it. The game loop continues on the next line.
From the game's perspective, start_music is a non-blocking call that
kicks off audio in the background. The game does not wait for aplay
to finish — aplay will keep playing the WAV file, looping if you
pass -l, until something stops it.
Build check
make re
./game questions.txtTier 1 music should now play as soon as the game starts. It will
continue until the binary exits (because stop_music still does
nothing). The next page implements stop_music.