Unix Programming

Table of Contents

References

1 Low-level IO

1.1 open

int open(const char *filename, int flags[, mode_t mode])

Create and return a file descriptor.

1.2 close

int close(int filedes)
  • file descriptor is deallocated
  • if all file descriptors associated with a pipe are closed, any unread data is discarded.

Return

  • 0 on success, -1 on failure

1.3 read

ssize_t read(int filedes, void *buffer, size_t size)
  • read up to size bytes, store result in buffer.

Return

  • number of bytes actually read.
  • return 0 means EOF

1.4 write

ssize_t write(int filedes, const void *buffer, size_t size)
  • write up to size bytes from buffer to the file descriptor.

Return

  • number of bytes actually written
  • -1 on failure

1.5 fdopen

FILE *fdopen(int filedes, const char *opentype)

from file descriptor, get the stream

1.6 fileno

int fileno(FILE *stream)

from stream to file descriptor

1.7 fdset

This is a bit array.

  • FDZERO(&fdset): initialise fdset to empty
  • FDCLR(fd, &fdset): remove fd from the set
  • FDSET(fd, &fdset): add fd to the set
  • FDISSET(fd, &fdset): return non-0 if fd is in set

1.8 select - synchronous I/O multiplexing

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout)

Block until at least one fd is true for specific condition, unless timeout.

Params

  • nfds: the range of file descriptors to be tested. Should be the largest one in the sets + 1. But just pass FD_SETSIZE.
  • readfds: watch for read. can be NULL.
  • writefds: watch for write. can be NULL.
  • errorfds: watch for error. can be NULL.
  • timeout:
    • NULL: no timeout, block forever
    • 0: return immediately. Used for test file descriptors

Return:

  • if timeout, return 0
  • the sets are modified. Those in sets are those ready
  • return the number of ready file descriptors in all sets
int fd;
// init fd

fd_set set;
FD_ZERO(&set)
FD_SET(fd, &set);

struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;

select(FD_SETSIZE, &set, NULL, NULL, &timeout);

1.9 sync

void sync(void) // sync all dirty files
int fsync(int filedes) // sync only that file

1.10 dup

You can create a new descriptor to refer to the same file. They

  • share file position
  • share status flag
  • seperate descriptor flags
int dup(int old)
// same as
fcntl(old, F_DUPFD, 0)

Copy old to the first available descriptor number.

int dup2(int old, int new)
// same as
close(new)
fcntl(old, F_DUPFD, new)

If old is invalid, it does nothing (does not close new)!

2 Date and Time

  • calendar time: absolute time, e.g. 2017/6/29
  • interval: between two calendar times
  • elapsed time: length of interval
  • amount of time: sum of elapsed times
  • period: elapsed time between two events
  • CPU time: like calendar time, but relative to process, i.e. when the process run on CPU
  • Processor time: amount of time a CPU is in use.

2.1 struct timeval

  • timet tvsec: seconds
  • long int tvusec: micro seconds, must be less than 1 million

2.2 struct timespec

  • timet tvsec
  • long int tvnsec: nanoseconds. Must be less than 1 billion

2.3 difftime

double difftime (time_t time1, time_t time0)

2.4 timet

On GNU it is long int. It should be the seconds elapsed since 00:00:00 Jan 1 1970, Coordinated Universal Time.

get current calenddar time:

time_t time(time_t *result)

2.5 alarm

2.5.1 struct itimerval

  • struct timeval itinterval: 0 to send alarm once, non-zero to send every interval
  • struct timeval itvalue: time left to alarm. If 0, the alarm is disabled

2.5.2 setitimer

int setitimer(int which, const struct itimerval *new, struct itimerval *old)
  • which: ITIMERREAL, ITIMERVIRTUAL, ITIMERPROF
  • new: set to new
  • old: if not NULL, fill with old value

2.5.3 getitimer(int which, struct itimerval *old)

get the timer

2.5.4 alarm

unsigned int alarm(unsigned int seconds)

To cancel existing alarm, use alarm(0). Return:

  • 0: no previous alarm
  • non-0: the remaining value of previous alarm
  unsigned int
  alarm (unsigned int seconds)
  {
    struct itimerval old, new;
    new.it_interval.tv_usec = 0;
    new.it_interval.tv_sec = 0;
    new.it_value.tv_usec = 0;
    new.it_value.tv_sec = (long int) seconds;
    if (setitimer (ITIMER_REAL, &new, &old) < 0)
      return 0;
    else
      return old.it_value.tv_sec;
  }

3 Process

Three steps

  • create child process
  • run an executable
  • coordinate the results with parent

3.1 system

int system(const char *command)
  • use sh to execute, and search in $PATH
  • return -1 on error
  • return the status code for the child

3.2 getpid

  • pidt getpid(void): return PID of current process
  • pidt getppid(void): PID of parent process

3.3 fork

pid_t fork(void)

return

  • 0 in child
  • child's PID in parent
  • -1 on error

3.4 exec

int execv (const char *filename, char *const argv[])
int execl (const char *filename, const char *arg0, ...)
int execve (const char *filename, char *const argv[], char *const env[])
int execle (const char *filename, const char *arg0, ..., char *const env[])
int execvp (const char *filename, char *const argv[])
int execlp (const char *filename, const char *arg0, ...)
  • execv: the last of argv array must be NULL. All strings are null-terminated.
  • execl: argv are seperated, the last one must be NULL
  • execve: provide env
  • execle
  • execvp: find filename in $PATH
  • execlp

3.5 wait

This should be used in parent process.

pid_t waitpid(pid_t pid, int *status_ptr, int options)
  • pid:
    • positive: the pid for a child process
    • -1 (WAITANY): any child process
    • 0 (WAITMYPGRP): any child process that has the same process group ID as the parent
    • -pgid (any other negative value): any child process having the process group ID as gpid
  • options: OR of the following
    • WNOHANG: no hang: the parent process should not wait
    • WUNTRACED: report stopped process as well as the terminated ones
  • return: PID of the child process that is reporting
pid_t wait(int *status_ptr)

wait(&status) is same as waitpid(-1, &status, 0)

3.5.1 Status

The signature is int NAME(int status).

  • WIFEXITED: if exited: return non-0 if child terminated normally with exit
  • WEXITSTATUS: exit status: if above true, this is the low-order 8 bits of the exit code
  • WIFSIGNALED: if signaled: non-0 if the process terminated because it receives a signal that was not handled
  • WTERMSIG: term sig: if above true, return that signal number
  • WCOREDUMP: core dump: non-0 if the child process terminated and produce a core dump
  • WIFSTOPPED: if stopped: if the child process stopped
  • WSTOPSIG: stop sig: if above true, return the signal number that cause the child to stop
3.5.1.1 TODO What is the difference between terminate and stop?

4 Tmp

4.1 poll - input/output multiplexing

int poll(struct pollfd fds[], nfds_t nfds, int timeout)

4.2 sigaction

  // handler must be void (*) (int)
  void handle_signal(int signal) {
    // should be alarm
    if (signal != SIGALRM) {
      std::cerr << "Wrong signal: " << signal << "\n";
    }
  }
  int main() {
    struct sigaction sa;
    sa.sa_handler = &handle_signal;
    sigaction(SIGALRM, &sa, NULL);
    ualarm(timeout_usec, 0);
  }

4.3 execvp

4.4 pipe

int pipe(int filedes[2])
  • Create a pipie and puts the filedes[0] for reading, filedes[1] for writing

Return:

  • 0 on success, -1 on failure

4.5 timeradd

void timeradd(struct timeval *a, struct timeval *b,
              struct timeval *res);
void timersub(struct timeval *a, struct timeval *b,
              struct timeval *res);
void timerclear(struct timeval *tvp);
int timerisset(struct timeval *tvp);
int timercmp(struct timeval *a, struct timeval *b, CMP);
  • timeradd: res = a+b
  • timersub: res = a-b

4.6 kill

int kill(pid_t pid, int sig)