Tidy up the formats.

This commit is contained in:
Mike Brady
2018-11-20 22:56:53 +00:00
parent 8f34c181e1
commit ccc4fe09af
7 changed files with 107 additions and 100 deletions
+22 -19
View File
@@ -883,9 +883,9 @@ int delay(long *the_delay) {
debug(1, "Error %d in delay(): \"%s\". Delay reported is %d frames.", reply,
snd_strerror(reply), *the_delay);
derr = snd_pcm_recover(alsa_handle, reply, 1);
if (derr < 0)
warn("Error %d -- could not clear an error after attempting delay(): \"%s\".", derr,
snd_strerror(derr));
if (derr < 0)
warn("Error %d -- could not clear an error after attempting delay(): \"%s\".", derr,
snd_strerror(derr));
frame_index = 0;
measurement_data_is_valid = 0;
@@ -913,9 +913,10 @@ int delay(long *the_delay) {
if ((derr = snd_pcm_prepare(alsa_handle))) {
debug(1, "Error preparing after delay error: \"%s\".", snd_strerror(derr));
derr = snd_pcm_recover(alsa_handle, derr, 1);
if (derr < 0)
warn("Error %d -- could not clear an error after attempting to recover following a delay(): \"%s\".", derr,
snd_strerror(derr));
if (derr < 0)
warn("Error %d -- could not clear an error after attempting to recover following a "
"delay(): \"%s\".",
derr, snd_strerror(derr));
}
}
}
@@ -964,10 +965,10 @@ static int play(void *buf, int samples) {
if (snd_pcm_state(alsa_handle) == SND_PCM_STATE_XRUN) {
if ((err = snd_pcm_prepare(alsa_handle))) {
debug(1, "Error preparing after underrun: \"%s\".", snd_strerror(err));
err = snd_pcm_recover(alsa_handle, err, 1);
if (err < 0)
warn("Error %d -- could not clear an error after detecting underrun in play(): \"%s\".", err,
snd_strerror(err));
err = snd_pcm_recover(alsa_handle, err, 1);
if (err < 0)
warn("Error %d -- could not clear an error after detecting underrun in play(): \"%s\".",
err, snd_strerror(err));
}
frame_index = 0; // we'll be starting over
measurement_data_is_valid = 0;
@@ -985,9 +986,10 @@ static int play(void *buf, int samples) {
debug(1, "Error %d writing %d samples in play(): \"%s\".", err, samples,
snd_strerror(err));
err = snd_pcm_recover(alsa_handle, err, 1);
if (err < 0)
warn("Error %d -- could not clear an error after attempting to write %d samples in play(): \"%s\".", err, samples,
snd_strerror(err));
if (err < 0)
warn("Error %d -- could not clear an error after attempting to write %d samples in "
"play(): \"%s\".",
err, samples, snd_strerror(err));
}
if (frame_index == 0) {
frames_sent_for_playing = samples;
@@ -1004,9 +1006,9 @@ static int play(void *buf, int samples) {
debug(1, "Error %d in delay in play(): \"%s\". Delay reported is %d frames.", err2,
snd_strerror(err2), fl);
err2 = snd_pcm_recover(alsa_handle, err2, 1);
if (err2 < 0)
warn("Error %d -- could not clear an error after checking delay in play(): \"%s\".", err2,
snd_strerror(err2));
if (err2 < 0)
warn("Error %d -- could not clear an error after checking delay in play(): \"%s\".",
err2, snd_strerror(err2));
frame_index = 0;
measurement_data_is_valid = 0;
} else {
@@ -1033,9 +1035,10 @@ static int play(void *buf, int samples) {
if ((err = snd_pcm_prepare(alsa_handle))) {
debug(1, "Error preparing after play error: \"%s\".", snd_strerror(err));
err2 = snd_pcm_recover(alsa_handle, err, 1);
if (err2 < 0)
warn("Error %d -- could not clear an error after reporting ALSA device in incorrect state for play: \"%s\".", err2,
snd_strerror(err2));
if (err2 < 0)
warn("Error %d -- could not clear an error after reporting ALSA device in incorrect "
"state for play: \"%s\".",
err2, snd_strerror(err2));
}
frame_index = 0;
measurement_data_is_valid = 0;
+17 -17
View File
@@ -123,7 +123,7 @@ void die(const char *format, ...) {
daemon_log(LOG_EMERG, "% 20.9f|*fatal error: %s", tss, s);
else
daemon_log(LOG_EMERG, "fatal error: %s", s);
pthread_setcancelstate(oldState,NULL);
pthread_setcancelstate(oldState, NULL);
exit(1);
}
@@ -152,7 +152,7 @@ void warn(const char *format, ...) {
daemon_log(LOG_WARNING, "% 20.9f|*warning: %s", tss, s);
else
daemon_log(LOG_WARNING, "%s", s);
pthread_setcancelstate(oldState,NULL);
pthread_setcancelstate(oldState, NULL);
}
void debug(int level, const char *format, ...) {
@@ -188,7 +188,7 @@ void debug(int level, const char *format, ...) {
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &currentState);
if (currentState == PTHREAD_CANCEL_ENABLE)
daemon_log(LOG_DEBUG, "Warning -- cancellation is enabled after logging");
pthread_setcancelstate(oldState,NULL);
pthread_setcancelstate(oldState, NULL);
}
void inform(const char *format, ...) {
@@ -216,7 +216,7 @@ void inform(const char *format, ...) {
daemon_log(LOG_INFO, "% 20.9f|%s", tss, s);
else
daemon_log(LOG_INFO, "%s", s);
pthread_setcancelstate(oldState,NULL);
pthread_setcancelstate(oldState, NULL);
}
// The following two functions are adapted slightly and with thanks from Jonathan Leffler's sample
@@ -607,7 +607,7 @@ int config_set_lookup_bool(config_t *cfg, char *where, int *dst) {
}
void command_set_volume(double volume) {
//this has a cancellation point if waiting is enabled
// this has a cancellation point if waiting is enabled
if (config.cmd_set_volume) {
/*Spawn a child to run the program.*/
pid_t pid = fork();
@@ -654,7 +654,7 @@ void command_set_volume(double volume) {
}
void command_start(void) {
//this has a cancellation point if waiting is enabled or a response is awaited
// this has a cancellation point if waiting is enabled or a response is awaited
if (config.cmd_start) {
pid_t pid;
int pipes[2];
@@ -722,7 +722,7 @@ void command_start(void) {
}
void command_stop(void) {
//this has a cancellation point if waiting is enabled
// this has a cancellation point if waiting is enabled
if (config.cmd_stop) {
/*Spawn a child to run the program.*/
pid_t pid = fork();
@@ -1112,7 +1112,7 @@ int sps_pthread_mutex_timedlock(pthread_mutex_t *mutex, useconds_t dally_time,
debug(debuglevel, "error %d: \"%s\" waiting for a mutex: \"%s\".", r,
strerror_r(r, errstr, sizeof(errstr)), debugmessage);
}
pthread_setcancelstate(oldState,NULL);
pthread_setcancelstate(oldState, NULL);
return r;
}
#endif
@@ -1145,13 +1145,13 @@ int sps_pthread_mutex_timedlock(pthread_mutex_t *mutex, useconds_t dally_time,
strerror_r(r, errstr, sizeof(errstr)), debugmessage);
}
}
pthread_setcancelstate(oldState,NULL);
pthread_setcancelstate(oldState, NULL);
return r;
}
#endif
int _debug_mutex_lock(pthread_mutex_t *mutex, useconds_t dally_time, const char *mutexname, const char *filename,
const int line, int debuglevel) {
int _debug_mutex_lock(pthread_mutex_t *mutex, useconds_t dally_time, const char *mutexname,
const char *filename, const int line, int debuglevel) {
if ((debuglevel > debuglev) || (debuglevel == 0))
return pthread_mutex_lock(mutex);
int oldState;
@@ -1169,15 +1169,15 @@ int _debug_mutex_lock(pthread_mutex_t *mutex, useconds_t dally_time, const char
uint64_t divisor = (uint64_t)1 << 32;
double delay = 1.0 * time_delay / divisor;
debug(debuglevel,
"mutex_lock \"%s\" at \"%s\" expected max wait: %0.9f, actual wait: %0.9f sec.", mutexname, dstring,
(1.0 * dally_time) / 1000000, delay);
"mutex_lock \"%s\" at \"%s\" expected max wait: %0.9f, actual wait: %0.9f sec.",
mutexname, dstring, (1.0 * dally_time) / 1000000, delay);
}
pthread_setcancelstate(oldState,NULL);
pthread_setcancelstate(oldState, NULL);
return result;
}
int _debug_mutex_unlock(pthread_mutex_t *mutex, const char *mutexname, const char *filename, const int line,
int debuglevel) {
int _debug_mutex_unlock(pthread_mutex_t *mutex, const char *mutexname, const char *filename,
const int line, int debuglevel) {
if ((debuglevel > debuglev) || (debuglevel == 0))
return pthread_mutex_unlock(mutex);
int oldState;
@@ -1191,7 +1191,7 @@ int _debug_mutex_unlock(pthread_mutex_t *mutex, const char *mutexname, const cha
if ((debuglevel != 0) && (r != 0))
debug(1, "error %d: \"%s\" unlocking mutex \"%s\" at \"%s\".", r,
strerror_r(r, errstr, sizeof(errstr)), mutexname, dstring);
pthread_setcancelstate(oldState,NULL);
pthread_setcancelstate(oldState, NULL);
return r;
}
+6 -6
View File
@@ -299,20 +299,20 @@ int sps_pthread_mutex_timedlock(pthread_mutex_t *mutex, useconds_t dally_time,
const char *debugmessage, int debuglevel);
// wait for the specified time, checking every 20 milliseconds, and block if it can't acquire the
// lock
int _debug_mutex_lock(pthread_mutex_t *mutex, useconds_t dally_time, const char *mutexName, const char *filename,
const int line, int debuglevel);
int _debug_mutex_lock(pthread_mutex_t *mutex, useconds_t dally_time, const char *mutexName,
const char *filename, const int line, int debuglevel);
#define debug_mutex_lock(mu, t, d) _debug_mutex_lock(mu, t, #mu , __FILE__, __LINE__, d)
#define debug_mutex_lock(mu, t, d) _debug_mutex_lock(mu, t, #mu, __FILE__, __LINE__, d)
int _debug_mutex_unlock(pthread_mutex_t *mutex, const char *mutexName, const char *filename, const int line,
int debuglevel);
int _debug_mutex_unlock(pthread_mutex_t *mutex, const char *mutexName, const char *filename,
const int line, int debuglevel);
#define debug_mutex_unlock(mu, d) _debug_mutex_unlock(mu, #mu, __FILE__, __LINE__, d)
void pthread_cleanup_debug_mutex_unlock(void *arg);
#define pthread_cleanup_debug_mutex_lock(mu, t, d) \
if (_debug_mutex_lock(mu, t, #mu, __FILE__, __LINE__, d) == 0) \
if (_debug_mutex_lock(mu, t, #mu, __FILE__, __LINE__, d) == 0) \
pthread_cleanup_push(pthread_cleanup_debug_mutex_unlock, (void *)mu)
char *get_version_string(); // mallocs a string space -- remember to free it afterwards
+31 -26
View File
@@ -454,7 +454,7 @@ void player_put_packet(seq_t seqno, uint32_t actual_timestamp, uint8_t *data, in
// now, if a flush_rtp_timestamp has been defined and the incoming timestamp is "before" it,
// drop it…
if ((conn->flush_rtp_timestamp != 0) && (actual_timestamp != conn->flush_rtp_timestamp) &&
if ((conn->flush_rtp_timestamp != 0) && (actual_timestamp != conn->flush_rtp_timestamp) &&
(modulo_32_offset(actual_timestamp, conn->flush_rtp_timestamp) <
conn->input_rate * 10)) { // if it's less than 10 seconds
debug(2, "Dropping flushed packet in player_put_packet, seqno %u, timestamp %" PRIu32
@@ -465,9 +465,9 @@ void player_put_packet(seq_t seqno, uint32_t actual_timestamp, uint8_t *data, in
conn->initial_reference_timestamp = 0;
} else {
if ((conn->flush_rtp_timestamp != 0) &&
(modulo_32_offset(conn->flush_rtp_timestamp, actual_timestamp) > conn->input_rate/5) &&
(modulo_32_offset(conn->flush_rtp_timestamp, actual_timestamp) > conn->input_rate / 5) &&
(modulo_32_offset(conn->flush_rtp_timestamp, actual_timestamp) < conn->input_rate)) {
// between 0.2 and 1 second
// between 0.2 and 1 second
debug(2, "Dropping flush request in player_put_packet");
conn->flush_rtp_timestamp = 0;
}
@@ -778,7 +778,6 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
local_time_now = get_absolute_time_in_fp(); // type okay
debug(3, "buffer_get_frame is iterating");
// if config.timeout (default 120) seconds have elapsed since the last audio packet was
// received, then we should stop.
// config.timeout of zero means don't check..., but iTunes may be confused by a long gap
@@ -832,10 +831,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
if (conn->ab_synced) {
curframe = conn->audio_buffer + BUFIDX(conn->ab_read);
if ((conn->ab_read != conn->ab_write) &&
(curframe->ready)) { // it could be synced and empty, under
// exceptional circumstances, with the
@@ -854,7 +850,8 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
}
}
if ((conn->flush_rtp_timestamp != 0) && (curframe->given_timestamp != conn->flush_rtp_timestamp) &&
if ((conn->flush_rtp_timestamp != 0) &&
(curframe->given_timestamp != conn->flush_rtp_timestamp) &&
(modulo_32_offset(curframe->given_timestamp, conn->flush_rtp_timestamp) <
conn->input_rate * 10)) { // if it's less than ten seconds
debug(2, "Dropping flushed packet in buffer_get_frame, seqno %u, timestamp %" PRIu32
@@ -868,13 +865,15 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
conn->initial_reference_timestamp = 0;
}
if ((conn->flush_rtp_timestamp != 0) &&
(modulo_32_offset(conn->flush_rtp_timestamp, curframe->given_timestamp) > conn->input_rate / 5) &&
(modulo_32_offset(conn->flush_rtp_timestamp, curframe->given_timestamp) < conn->input_rate * 10 )) {
(modulo_32_offset(conn->flush_rtp_timestamp, curframe->given_timestamp) >
conn->input_rate / 5) &&
(modulo_32_offset(conn->flush_rtp_timestamp, curframe->given_timestamp) <
conn->input_rate * 10)) {
debug(2, "Dropping flush request in buffer_get_frame");
conn->flush_rtp_timestamp = 0;
}
}
if ((curframe) && (curframe->ready)) {
notified_buffer_empty = 0; // at least one buffer now -- diagnostic only.
if (conn->ab_buffering) { // if we are getting packets but not yet forwarding them to the
@@ -1401,12 +1400,14 @@ typedef struct stats { // statistics for running averages
void player_thread_initial_cleanup_handler(__attribute__((unused)) void *arg) {
rtsp_conn_info *conn = (rtsp_conn_info *)arg;
debug(3, "Connection %d: player thread main loop exit via player_thread_initial_cleanup_handler.", conn->connection_number);
debug(3, "Connection %d: player thread main loop exit via player_thread_initial_cleanup_handler.",
conn->connection_number);
}
void player_thread_cleanup_handler(void *arg) {
rtsp_conn_info *conn = (rtsp_conn_info *)arg;
debug(3, "Connection %d: player thread main loop exit via player_thread_cleanup_handler.", conn->connection_number);
debug(3, "Connection %d: player thread main loop exit via player_thread_cleanup_handler.",
conn->connection_number);
if (config.statistics_requested) {
int rawSeconds = (int)difftime(time(NULL), conn->playstart);
@@ -1758,8 +1759,9 @@ void *player_thread_func(void *arg) {
debug(2, "Play begin");
while (1) {
pthread_testcancel(); // allow a pthread_cancel request to take effect.
abuf_t *inframe = buffer_get_frame(conn); // this has cancellation point(s), but it's not guaranteed that they'll aways be executed
pthread_testcancel(); // allow a pthread_cancel request to take effect.
abuf_t *inframe = buffer_get_frame(conn); // this has cancellation point(s), but it's not
// guaranteed that they'll aways be executed
if (inframe) {
inbuf = inframe->data;
inbuflength = inframe->length;
@@ -1898,8 +1900,8 @@ void *player_thread_func(void *arg) {
int64_t rt, nt;
rt = reference_timestamp; // uint32_t to int64_t
nt = inframe->given_timestamp; // uint32_t to int64_t
rt = rt*conn->output_sample_ratio;
nt = nt*conn->output_sample_ratio;
rt = rt * conn->output_sample_ratio;
nt = nt * conn->output_sample_ratio;
uint64_t local_time_now = get_absolute_time_in_fp(); // types okay
// struct timespec tn;
@@ -2048,15 +2050,18 @@ void *player_thread_func(void *arg) {
// sync_error_out_of_bounds, sync_error);
sync_error_out_of_bounds = 0;
int64_t filler_length = (int64_t)(config.resyncthreshold * config.output_rate); // number of samples
int64_t filler_length =
(int64_t)(config.resyncthreshold * config.output_rate); // number of samples
if ((sync_error > 0) && (sync_error > filler_length)) {
debug(2, "Large positive sync error: %" PRId64 ".", sync_error);
int64_t local_frames_to_drop = sync_error / conn->output_sample_ratio;
uint32_t frames_to_drop_sized = local_frames_to_drop;
do_flush(inframe->given_timestamp+frames_to_drop_sized,conn);
do_flush(inframe->given_timestamp + frames_to_drop_sized, conn);
} else if ((sync_error < 0) && ((-sync_error) > filler_length)) {
debug(2, "Large negative sync error: %" PRId64 " with should_be_frame_32 of %" PRIu32
", nt of %" PRId64 " and current_delay of %" PRId64 ".", sync_error, should_be_frame_32, nt, current_delay);
debug(2,
"Large negative sync error: %" PRId64 " with should_be_frame_32 of %" PRIu32
", nt of %" PRId64 " and current_delay of %" PRId64 ".",
sync_error, should_be_frame_32, nt, current_delay);
int64_t silence_length = -sync_error;
if (silence_length > (filler_length * 5))
silence_length = filler_length * 5;
@@ -2064,7 +2069,7 @@ void *player_thread_func(void *arg) {
char *long_silence = malloc(conn->output_bytes_per_frame * silence_length_sized);
if (long_silence) {
memset(long_silence, 0, conn->output_bytes_per_frame * silence_length_sized);
debug(2,"Play a silence of %d frames.",silence_length_sized);
debug(2, "Play a silence of %d frames.", silence_length_sized);
config.output->play(long_silence, silence_length_sized);
free(long_silence);
} else {
@@ -2464,7 +2469,7 @@ void *player_thread_func(void *arg) {
pthread_cleanup_pop(1); // pop the cleanup handler
debug(1, "This should never be called either.");
pthread_cleanup_pop(1); // pop the initial cleanup handler
pthread_exit(NULL);
pthread_exit(NULL);
}
// takes the volume as specified by the airplay protocol
@@ -2777,12 +2782,12 @@ int player_stop(rtsp_conn_info *conn) {
debug(2, "pend");
send_ssnc_metadata('pend', NULL, 0, 1); // contains cancellation points
#endif
debuglev = dl;
debuglev = dl;
command_stop();
return 0;
} else {
debug(3, "Connection %d: player thread already deleted.", conn->connection_number);
debuglev = dl;
debuglev = dl;
return -1;
}
}
+5 -4
View File
@@ -621,13 +621,14 @@ void *rtp_timing_receiver(void *arg) {
distant_transmit_time = (uint64_t)nctohl(&packet[24]) << 32;
distant_transmit_time += nctohl(&packet[28]);
uint64_t remote_processing_time = 0;
if (distant_transmit_time >= distant_receive_time)
remote_processing_time = distant_transmit_time - distant_receive_time;
remote_processing_time = distant_transmit_time - distant_receive_time;
else {
debug(1, "Yikes: distant_transmit_time is before distant_receive_time; remote processing time set to zero.");
debug(1, "Yikes: distant_transmit_time is before distant_receive_time; remote "
"processing time set to zero.");
}
// debug(1,"Return trip time: %" PRIu64 " uS, remote processing time: %" PRIu64 "
// uS.",(return_time*1000000)>>32,(remote_processing_time*1000000)>>32);
+24 -26
View File
@@ -667,7 +667,7 @@ int msg_write_response(int fd, rtsp_message *resp) {
pktfree -= n;
p += n;
if (pktfree <= 1024) {
debug(1,"Attempted to write overlong RTSP packet 1");
debug(1, "Attempted to write overlong RTSP packet 1");
return -1;
}
}
@@ -680,7 +680,7 @@ int msg_write_response(int fd, rtsp_message *resp) {
pktfree -= n;
p += n;
if (pktfree <= 1024) {
debug(1,"Attempted to write overlong RTSP packet 2");
debug(1, "Attempted to write overlong RTSP packet 2");
return -2;
}
debug(1, "Content is \"%s\"", resp->content);
@@ -694,7 +694,7 @@ int msg_write_response(int fd, rtsp_message *resp) {
p += n;
if (pktfree <= 1024) {
debug(1,"Attempted to write overlong RTSP packet 3");
debug(1, "Attempted to write overlong RTSP packet 3");
return -3;
}
if (write(fd, pkt, p - pkt) != p - pkt) {
@@ -1955,7 +1955,7 @@ void rtsp_conversation_thread_cleanup_function(void *arg) {
// debug(1, "Connection %d: rtsp_conversation_thread_func_cleanup_function called.",
// conn->connection_number);
if (conn->player_thread)
player_stop(conn);
player_stop(conn);
if (conn->fd > 0) {
// debug(1, "Connection %d: closing fd %d.",
// conn->connection_number,conn->fd);
@@ -2067,24 +2067,23 @@ static void *rtsp_conversation_thread_func(void *pconn) {
if (method_selected == 0) {
debug(1, "RTSP thread %d: Unrecognised and unhandled rtsp request \"%s\".",
conn->connection_number, req->method);
int y = req->contentlength;
if (y > 0) {
char obf[4096];
if (y > 4096)
y = 4096;
char *p = req->content;
char *obfp = obf;
int obfc;
for (obfc = 0; obfc < y; obfc++) {
snprintf(obfp, 3, "%02X", (unsigned int)*p);
p++;
obfp += 2;
};
*obfp = 0;
debug(1, "Content: \"%s\".",obf);
}
int y = req->contentlength;
if (y > 0) {
char obf[4096];
if (y > 4096)
y = 4096;
char *p = req->content;
char *obfp = obf;
int obfc;
for (obfc = 0; obfc < y; obfc++) {
snprintf(obfp, 3, "%02X", (unsigned int)*p);
p++;
obfp += 2;
};
*obfp = 0;
debug(1, "Content: \"%s\".", obf);
}
}
}
debug(debug_level, "RTSP thread %d: RTSP Response:", conn->connection_number);
@@ -2099,8 +2098,8 @@ static void *rtsp_conversation_thread_func(void *pconn) {
if (conn->stop == 0) {
int err = msg_write_response(conn->fd, resp);
if (err) {
debug(1,"A communication error was detected. Closing the play session.");
player_stop(conn);
debug(1, "A communication error was detected. Closing the play session.");
player_stop(conn);
}
}
pthread_cleanup_pop(1);
@@ -2212,14 +2211,13 @@ void rtsp_listen_loop(void) {
// See: https://github.com/mikebrady/shairport-sync/issues/329
fcntl(fd, F_SETFD, FD_CLOEXEC);
ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
struct timeval tv;
tv.tv_sec = 3; // three seconds write timeout
tv.tv_usec = 0;
if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tv, sizeof tv) == -1)
debug(1, "Error %d setting send timeout for rtsp writeback.", errno);
#ifdef IPV6_V6ONLY
// some systems don't support v4 access on v6 sockets, but some do.
// since we need to account for two sockets we might as well
+2 -2
View File
@@ -25,8 +25,6 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
@@ -37,7 +35,9 @@
#include <popt.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>