Sysprog 11

1,542 views

Published on

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,542
On SlideShare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
20
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Sysprog 11

  1. 1. C/C++ Linux System Programming <ul><ul><li>Session 11 </li></ul></ul><ul><ul><li>User-space System Programming </li></ul></ul><ul><ul><li> – session 1 </li></ul></ul>
  2. 2. Outline <ul><li>Generic OS Process concepts </li></ul><ul><li>API for process creation and execution </li></ul><ul><li>Signals </li></ul><ul><li>Job Control </li></ul><ul><li>Scheduling </li></ul>
  3. 3. Applicability <ul><li>OS </li></ul><ul><li>POSIX </li></ul><ul><li>Portability </li></ul><ul><li>References </li></ul><ul><ul><li>Modern Operating Systems - Tanenbaum </li></ul></ul><ul><ul><li>Advanced Programming in the UNIX Environment – Richard Stevens </li></ul></ul><ul><ul><li>Advanced Linux Programming – Mitchel et al </li></ul></ul><ul><ul><li>Linux System Programming – Robert Lowe </li></ul></ul>
  4. 4. errno <ul><li>Typical return strategy on system calls </li></ul><ul><ul><li>0 on success </li></ul></ul><ul><ul><li>-1 on errno, errno is set </li></ul></ul><ul><li>Global errno </li></ul><ul><ul><li>char *strerror(int errnum); </li></ul></ul><ul><ul><li>char *strerror_r(int errnum, char *buf, size_t buflen); </li></ul></ul><ul><ul><li>void perror(const char *s); </li></ul></ul><ul><li>Common error codes – context dependent </li></ul>
  5. 5. Process <ul><li>Program in Execution </li></ul><ul><li>Address space </li></ul><ul><li>PID </li></ul><ul><ul><li>pid_t getpid(void); </li></ul></ul><ul><li>Tools </li></ul><ul><ul><li>/proc </li></ul></ul><ul><ul><li>ps </li></ul></ul><ul><ul><li>top </li></ul></ul>
  6. 6. Process Relationships <ul><li>Parent/Child </li></ul><ul><ul><li>Starting the process </li></ul></ul><ul><ul><ul><li>pid_t getppid(void); </li></ul></ul></ul><ul><ul><li>Cleanup responsibility </li></ul></ul><ul><li>Process group </li></ul><ul><ul><li>Job control </li></ul></ul>
  7. 7. fork – A new process <ul><li>Dup address space </li></ul><ul><li>Return child pid in parent, 0 in child </li></ul><ul><li>Copy on write (vfork) </li></ul><ul><li>gdb: set fork-follow-mode <parent/child> </li></ul>pid = fork(); if (pid < 0) { TRACE((&quot;Fork failed, errno=%d&quot;, errno)); if (jp) freejob(jp); ash_msg_and_raise_error(&quot;can't fork&quot;); } if (pid == 0) forkchild(jp, /*n,*/ mode); else forkparent(jp, n, mode, pid); <ul><li>busybox/ash.c: </li></ul>
  8. 8. exec – Letting the child go <ul><li>On success, no return </li></ul><ul><li>New address space </li></ul><ul><li>Execve – env </li></ul><ul><li>exec(l/v)(e)(p) – l: valist, v: char*[], e:env, p: PATH </li></ul><ul><ul><li>int execve(const char *filename, char *const argv[], char *const envp[]); </li></ul></ul>
  9. 9. Exec Cont'd <ul><li>Retains kernel representation </li></ul><ul><ul><li>e.g. file descriptors, pid, priority </li></ul></ul><ul><li>Loses user-space settings and byproducts </li></ul><ul><ul><li>e.g. mapped files </li></ul></ul><ul><li>Why not spawn (fork + exec)? </li></ul>
  10. 10. User/Group Ids <ul><li>/etc/password, /etc/group </li></ul><ul><li>setuid binaries </li></ul><ul><li>Minimal Privilege Concept </li></ul><ul><li>Real: Owner of original process </li></ul><ul><li>Effective: Currently executing (This is what is checked) </li></ul><ul><li>Remember stack overflows!! </li></ul><ul><ul><li>http://insecure.org/stf/smashstack.html </li></ul></ul>
  11. 11. Ids and fork/exec <ul><li>fork inherits all </li></ul><ul><li>exec inherits real, switches effective on setuid bins </li></ul><ul><li>Saved ID: at time of exec </li></ul><ul><li>Rules </li></ul><ul><ul><li>Root: anything </li></ul></ul><ul><ul><li>Other: saved or real </li></ul></ul>
  12. 12. setuid API <ul><li>POSIX </li></ul><ul><ul><li>int setuid(uid_t uid); //all 3 </li></ul></ul><ul><ul><li>int seteuid(uid_t euid); //eff </li></ul></ul><ul><li>Non-POSIX </li></ul><ul><ul><li>int setreuid(uid_t ruid, uid_t euid); </li></ul></ul><ul><ul><li>int setresuid(uid_t ruid, uid_t euid, uid_t suid); </li></ul></ul>
  13. 13. Config <ul><li>Environment variables </li></ul><ul><ul><li>char *getenv(const char *name); </li></ul></ul><ul><ul><li>int setenv(const char *name, const char *value, int overwrite); </li></ul></ul><ul><ul><li>int unsetenv(const char *name); </li></ul></ul><ul><ul><li>int putenv(char *string); </li></ul></ul><ul><ul><li>extern char **environ </li></ul></ul><ul><li>Sysconf </li></ul><ul><ul><li>long sysconf(int name); </li></ul></ul>
  14. 14. Signals <ul><li>Asynchronous IPC mechanism </li></ul><ul><li>Atomic: scheduler's context </li></ul><ul><li>Common signals </li></ul><ul><li>Process behavior toward signals </li></ul><ul><ul><li>Ignore/Mask/Handle/Default </li></ul></ul><ul><ul><li>SIGKILL/SIGSTOP </li></ul></ul>
  15. 15. exit – Process termination <ul><li>Clean exit </li></ul><ul><ul><li>Return from main </li></ul></ul><ul><ul><li>Exit call (why if I can just return?) </li></ul></ul><ul><ul><ul><li>void exit(int status); </li></ul></ul></ul><ul><li>Exit status </li></ul><ul><ul><li>EXIT_SUCCESS/EXIT_FAILURE </li></ul></ul><ul><li>Non clean exit </li></ul>
  16. 16. atexit static void mke2fs_clean_up(void) { if (ENABLE_FEATURE_CLEAN_UP && journal_device) free(journal_device); } int mke2fs_main (int argc, char **argv) { .... if (ENABLE_FEATURE_CLEAN_UP) atexit(mke2fs_clean_up); .... } <ul><li>Atexit </li></ul><ul><li>What pattern is this? </li></ul>int atexit(void (*function)(void));
  17. 17. wait – Responsible parenting <ul><li>Wait family </li></ul><ul><ul><li>pid_t wait(int *status); </li></ul></ul><ul><ul><li>pid_t waitpid(pid_t pid, int *status, int options); </li></ul></ul><ul><li>Zombies: Fruit of negligent parents </li></ul><ul><li>SIGCHLD </li></ul>
  18. 18. Wait example – sshd pid = fork(); if (pid == -1) { fatal(&quot;fork of unprivileged child failed&quot;); } else if (pid != 0) { debug2(&quot;Network child is on pid %ld&quot;, (long)pid); close(pmonitor->m_recvfd); pmonitor->m_pid = pid; monitor_child_preauth(authctxt, pmonitor); close(pmonitor->m_sendfd); /* Sync memory */ monitor_sync(pmonitor); /* Wait for the child's exit status */ while (waitpid(pid, &status, 0) < 0) if (errno != EINTR) break; return (1); } else {
  19. 19. Job Control <ul><li>Process Group: for signals (consider | ) </li></ul><ul><ul><li>int setpgid(pid_t pid, pid_t pgid); // 0 current </li></ul></ul><ul><li>Sessions: for terminal association </li></ul><ul><ul><li>pid_t setsid(void); // not for pg leaders </li></ul></ul><ul><li>Leaders </li></ul><ul><li>int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); </li></ul>
  20. 20. Interesting Example - busybox/init.c if (pid > 0) { /* Parent - wait till the child is done */ bb_signals(0 + (1 << SIGINT) + (1 << SIGTSTP) + (1 << SIGQUIT) , SIG_IGN); signal(SIGCHLD, SIG_DFL); waitfor(pid); /* See if stealing the controlling tty back is necessary */ if (tcgetpgrp(0) != getpid()) _exit(EXIT_SUCCESS); /* Use a temporary process to steal the controlling tty. */ pid = fork(); if (pid < 0) { message(L_LOG | L_CONSOLE, &quot;can't fork&quot;); _exit(EXIT_FAILURE); } if (pid == 0) { setsid(); ioctl(0, TIOCSCTTY, 1); _exit(EXIT_SUCCESS); } waitfor(pid); _exit(EXIT_SUCCESS); } /* Child - fall though to actually execute things */
  21. 21. Daemons or Independent children <ul><li>Reparenting to init – how? </li></ul><ul><li>No controlling tty – how do I make sure? </li></ul><ul><li>Some gotchas: </li></ul><ul><ul><li>Directory </li></ul></ul><ul><ul><li>File descriptor </li></ul></ul><ul><ul><li>Logging </li></ul></ul><ul><li>int daemon(int nochdir, int noclose); // Non-POSIX </li></ul>
  22. 22. Sending Signals <ul><li>int kill(pid_t pid, int sig); </li></ul><ul><li>int raise(int sig); // = kill(getpid(), sig); </li></ul><ul><li>int sigqueue(pid_t pid, int sig, const union sigval value); // value is a payload (IPC w/data!!) </li></ul>
  23. 23. Handling Signals – old school <ul><li>Handler </li></ul><ul><ul><li>typedef void (*sighandler_t)(int); </li></ul></ul><ul><ul><li>sighandler_t signal(int signum, sighandler_t handler); </li></ul></ul><ul><ul><li>SIG_IGN / SIG_DFL </li></ul></ul>static void main_sigchld_handler(int sig) { int save_errno = errno; pid_t pid; int status; while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || (pid < 0 && errno == EINTR)) ; signal(SIGCHLD, main_sigchld_handler); errno = save_errno; }
  24. 24. Signal sets <ul><ul><li>int sigemptyset(sigset_t *set); // Init </li></ul></ul><ul><ul><li>int sigfillset(sigset_t *set); // Init with all </li></ul></ul><ul><ul><li>int sigaddset(sigset_t *set, int signum); </li></ul></ul><ul><ul><li>int sigdelset(sigset_t *set, int signum); </li></ul></ul><ul><ul><li>int sigismember(const sigset_t *set, int signum); </li></ul></ul><ul><ul><li>Non-POSIX: </li></ul></ul><ul><ul><ul><li>int sigisemptyset (sigset_t *set); </li></ul></ul></ul><ul><ul><ul><li>int sigorset (sigset_t *dest, sigset_t *left, sigset_t *right); </li></ul></ul></ul><ul><ul><ul><li>int sigandset (sigset_t *dest, sigset_t *left, sigset_t *right); </li></ul></ul></ul>
  25. 25. Masking <ul><li>Mask/Unmask </li></ul><ul><ul><li>int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); </li></ul></ul><ul><ul><li>how: SIG_BLOCK/SIG_UNBLOCK/SIG_SETMASK </li></ul></ul><ul><li>Check pending (temporarily masked) </li></ul><ul><ul><li>int sigpending(sigset_t *set); </li></ul></ul><ul><li>Waiting for a signal </li></ul><ul><ul><li>int pause(void); </li></ul></ul><ul><ul><li>int sigsuspend(const sigset_t *mask); </li></ul></ul>
  26. 26. Masking Example - ssh/server_loop.c /* block SIGCHLD while we check for dead children */ sigemptyset(&nset); sigaddset(&nset, SIGCHLD); sigprocmask(SIG_BLOCK, &nset, &oset); if (child_terminated) { debug(&quot;Received SIGCHLD.&quot;); while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || (pid < 0 && errno == EINTR)) if (pid > 0) session_close_by_pid(pid, status); child_terminated = 0; } sigprocmask(SIG_SETMASK, &oset, NULL); }
  27. 27. Versatile Signal Handling Interface <ul><li>int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); </li></ul><ul><li>Important sigaction fields: </li></ul><ul><ul><li>void (*sa_handler)(int); </li></ul></ul><ul><ul><li>void (*sa_sigaction)(int, siginfo_t *, void *); </li></ul></ul><ul><ul><li>sigset_t sa_mask; </li></ul></ul><ul><li>Important siginfo_t: </li></ul><ul><ul><li>si_signo , si_uid, si_value, si_addr </li></ul></ul>
  28. 28. Example - inetd memset(&sa, 0, sizeof(sa)); sigaddset(&sa.sa_mask, SIGALRM); sigaddset(&sa.sa_mask, SIGCHLD); sigaddset(&sa.sa_mask, SIGHUP); sa.sa_handler = retry_network_setup; sigaction_set(SIGALRM, &sa); sa.sa_handler = reread_config_file; sigaction_set(SIGHUP, &sa); sa.sa_handler = reap_child; sigaction_set(SIGCHLD, &sa); sa.sa_handler = clean_up_and_exit; sigaction_set(SIGTERM, &sa); sa.sa_handler = clean_up_and_exit; sigaction_set(SIGINT, &sa); sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, &saved_pipe_handler); static void clean_up_and_exit(int sig UNUSED_PARAM) { servtab_t *sep; /* XXX signal race walking sep list */ for (sep = serv_list; sep; sep = sep->se_next) { if (sep->se_fd == -1) continue; switch (sep->se_family) { case AF_UNIX: unlink(sep->se_service); break; default: /* case AF_INET, AF_INET6 */ #if ENABLE_FEATURE_INETD_RPC if (sep->se_wait == 1 && is_rpc_service(sep)) unregister_rpc(sep); /* XXX signal race */ #endif break; } if (ENABLE_FEATURE_CLEAN_UP) close(sep->se_fd); } remove_pidfile(_PATH_INETDPID); exit(EXIT_SUCCESS); }
  29. 29. Some Signal Notes <ul><li>Behavior in fork </li></ul><ul><li>Behavior in exec </li></ul><ul><li>Process Group relevance </li></ul><ul><li>System call interruptions </li></ul><ul><li>Intro to race conditions </li></ul><ul><ul><li>Critical region </li></ul></ul><ul><ul><li>Reentrancy </li></ul></ul><ul><ul><li>Minimal work </li></ul></ul><ul><ul><li>Sigatomic_t </li></ul></ul>
  30. 30. system/popen <ul><li>fork/exec (/bin/sh) </li></ul><ul><li>Security hole </li></ul><ul><li>Signal blocking </li></ul>
  31. 31. Scheduling <ul><li>Time-sharing (timeslices) </li></ul><ul><li>States </li></ul><ul><li>Process table </li></ul><ul><li>Context switch </li></ul><ul><li>Priorities </li></ul><ul><li>Preemption </li></ul>
  32. 32. Scheduling (for now) <ul><li>nice/renice </li></ul><ul><li>Relinquishing CPU </li></ul><ul><ul><li>schedule_yield </li></ul></ul><ul><ul><li>sleep </li></ul></ul>
  33. 33. Real-time Scheduling <ul><li>Real-time </li></ul><ul><ul><li>soft/hard </li></ul></ul><ul><ul><li>O(1) – deterministic performance </li></ul></ul><ul><li>Priorities </li></ul><ul><li>Scheduling classes </li></ul>
  34. 34. Time
  35. 35. Alarms

×