Title: CS 241 Section Week
1CS 241 Section Week 9(10/23/08)
2Outline
- MP5 preview
- Signals
- Threads
- pause(), sigwait()
- POSIXTMR timers
- Memory
3MP5 Preview
4MP5 Preview
- For success on this MP
- Carefully read Readme.txt for details!
- We provide you with some in built-in test cases
so you can see whether your implementation is
correct. - Requires a good understanding of concepts of Unix
process and signal handling ( fork(), exec(),
wait() ) - Good luck!
5Signals
6Signals
- A signal is a software notification to a process
of an event. - Signals are asynchronous, so the process can
handle them no matter where it is in the program.
7User-triggered signals
- CtrlC triggers SIGINT
- CtrlZ triggers SIGSTOP
- CtrlD triggers SIGQUIT
- etc.
- Run stty -a to see others.
8Sending signals from the command line
- The Unix kill command sends signals.
- The usage is
- kill -ltsignalgt ltpidgt
- Run kill -l to see available signals.
- The command is called kill because in many cases
the default behavior is for the process receiving
the signal to die.
9Sending signals from inside the program
- Use the kill() function to send signals from one
process to another. - include ltsys/types.hgt
- include ltsignal.hgt
- int kill(pid_t pid, int sig)
- Examples
- kill(getpid(),SIGTERM)
- kill(getppid(),SIGKILL)
10- include ltstdio.hgt
- include ltsys/types.hgt
- include ltsignal.hgt
- int shift 1
- int main(int argc, char argv)
- char c
- while(1)
- c getchar()
- if (cgt'a' c lt 'z')
- c shift
- while (c gt 'z')
- c - 26
- else if (cgt'A' c lt 'Z')
- c shift
- while(c gt 'Z')
- c - 26
-
- putchar(c)
-
- This example takes in input one character at a
time, and shifts the letters forward by one. - If you run this program you can
- Send it signals using CtrlC, CtrlZ, etc.
- The kill command, from another window
11Signal blocking
- We can block some signals, so they dont reach
the process right away. - The calls used are
- sigemptyset(newsigset)
- sigaddset(newsigset,SIGINT)
- sigprocmask(SIG_BLOCK,newsigset,NULL)
12- include ltstdio.hgt
- include ltsys/types.hgt
- include ltsignal.hgt
- int shift 1
- int main(int argc, char argv)
- char c
-
Blocking SIGINT.
sigset_t newsigset // Turn off SIGINT if
(sigemptyset(newsigset) -1)
perror("Can't set new mask.") else
if (sigaddset(newsigset,SIGINT) -1)
perror("Can't set signal set.")
else if (sigprocmask(SIG_BLOCK,newsigset,NULL)
-1) perror("Can't block INT signal.")
while(1) c getchar() if (cgt'a' c lt
'z') c shift while (c gt
'z') c - 26 else if (cgt'A' c
lt 'Z') c shift while(c gt
'Z') c - 26 putchar(c)
- This program does not respond to CtrlC. You
will need to send it a SIGKILL signal to kill it,
because the SIGINT signal has been blocked - (Note some signals, such as SIGKILL, cannot be
blocked.)
13Signal sets
- A sigset_t is a set of signals, represented as a
bit array. - The functions sigemptyset, sigfillset, sigaddset,
and sigdelset set and change the signal set.
14Signal Mask
- The signal mask is the set of signals that are
currently blocked. sigprocmask changes the
signal mask - sigprocmask(SIG_BLOCK,newset,oldset) blocks all
signals in newset. - sigprocmask(SIG_UNBLOCK,newset,oldset) unblocks
all signals not in newset. - sigprocmask(SIG_SETMASK,newset,oldset) blocks
all signals in newset, and unblocks all signals
not in newset.
15include ltstdio.hgt include ltsys/types.hgt include
ltsignal.hgt int shift 1
static void change_shift(int sig) shift
We can change what happens when a process
receives a signal.
- int main(int argc, char argv)
- struct sigaction act
- sigset_t newsigset
- char c
- // Turn off SIGINT
- if (sigemptyset(newsigset) -1)
perror("Can't set new mask.") - else if (sigaddset(newsigset,SIGINT)
-1) - perror("Can't set signal set.")
- else if (sigprocmask(SIG_BLOCK,newsigset
,NULL) -1) - perror("Can't block INT signal.")
-
// Add hadler for SIGUSR1 act.sa_handler
change_shift act.sa_flags 0 if(sigemptyset(ac
t.sa_mask) 1 sigaction(SIGUSR1, act,
NULL)-1) perror("Can't set SIGUSR1
handler") return -1
while(1) c getchar() if (cgt'a' c lt
'z') c shift while (c gt
'z') c - 26 else if (cgt'A' c
lt 'Z') c shift while(c gt
'Z') c - 26 putchar(c)
- Every time the process receives the signal
SIGUSR1, it calls the change_shift function,
which changes the shift value. - act.sa_handler change_shift
- act.sa_flags 0
- sigemptyset(act.sa_mask)
- sigaction(SIGUSR1, act, NULL)
16Signal Actions
- In the struct sigaction act
- sa_handler is the function called upon receiving
the signal - sa_flags are special flags
- sa_mask are the additional signals to block while
handling this signal - sigaction(SIGUSR1, act1, NULL) associates this
handler with SIGUSR1.
17Summary SIGNALS
- Asynchronous notification to a process indicating
some action should be taken - Sending signals to a process
- kill -ltsignalgt ltpidgt
- int kill(pid_t pid, int sig)
- We can signal individual threads, too
- int pthread_kill(thread_t tid, int sig)
18Process Signal Masks
- Setting SIGINT to be blocked
- if ((sigemptyset(set) -1)
- (sigaddset(set, SIGINT) -1))
- perror(Failed init signal set)
- else if
- (sigprocmask(SIG_BLOCK, set, oldset) -1)
- perror(Failed to block SIGINT)
- SIG_BLOCK adds set to current mask
- oldset will store the previous signal mask
19Threads
20Thread Signal Masks
- pthread_sigmask()
- Takes same parameters as sigprocmask
- Only affects the signal mask of a single thread
- Signal mask is inherited on thread creation
21- void handler(int sig)
- pthread_exit(NULL)
-
- void hello_thread(void arg)
- // this thread should exit on SIGUSR1
- for ()
- printf("Hello\n")
- sleep(5)
-
- return NULL
-
- void world_thread(void arg)
- // this thread should exit on SIGUSR2
- for ()
- printf("World\n")
- sleep(5)
-
- return NULL
-
How can you change the code to stop the hello
thread when receiving SIGUSR1 and the world
thread when receiving SIGUSR2 ?
22- void handler(int sig)
- pthread_exit(NULL)
-
- void hello_thread(void arg)
- // this thread should exit on SIGUSR1
- for ()
- printf("Hello\n")
- sleep(5)
-
- return NULL
-
- void world_thread(void arg)
- // this thread should exit on SIGUSR2
- for ()
- printf("World\n")
- sleep(5)
-
- return NULL
-
How can you change the code to stop the hello
thread when receiving SIGUSR1 and the world
thread when receiving SIGUSR2 ?
- Hint 1 you should not have to change the signal
handler - Hint 2 what about the main thread?
23- void handler(int sig)
- pthread_exit(NULL)
-
- void hello_thread(void arg)
- // this thread should exit on SIGUSR1
- for ()
- printf("Hello\n")
- sleep(5)
-
- return NULL
-
- void world_thread(void arg)
- // this thread should exit on SIGUSR2
- for ()
- printf("World\n")
- sleep(5)
-
- return NULL
-
void handler(int sig) pthread_exit(NULL) voi
d hello_thread(void arg)
// unblock SIGUSR1 for this thread sigset_t
set sigemptyset(set) sigaddset(set,
SIGUSR1) pthread_sigmask(SIG_UNBLOCK, set,
NULL)
for () printf("Hello\n") sleep(5)
return NULL void world_thread(void arg)
// unblock SIGUSR2 for this thread sigset_t
set sigemptyset(set) sigaddset(set,
SIGUSR2) pthread_sigmask(SIG_UNBLOCK, set,
NULL)
for () printf("World\n") sleep(5) r
eturn NULL int main(int argc, char
argv) pthread_t hello, world struct
sigaction act act.sa_flags 0 act.sa_handler
handler sigemptyset(act.sa_mask) sigaction(
SIGUSR1, act, NULL) sigaction(SIGUSR2, act,
NULL)
// block SIGUSR1 and SIGUSR2 for all three
threads sigset_t set sigemptyset(set) sigadd
set(set, SIGUSR1) sigaddset(set,
SIGUSR2) sigprocmask(SIG_BLOCK, set, NULL)
pthread_create(hello, NULL, hello_thread,
NULL) pthread_create(world, NULL,
world_thread, NULL) pthread_join(hello,
NULL) pthread_join(world, NULL) return
EXIT_SUCCESS
24Signal Handlers
- Allow us to change what happens when a signal is
received - void handler(int signo)
- struct sigaction act
- act.sa_flags 0
- act.sa_handler handler
- // additional signals blocked in the handler
- sigemptyset(act.sa_mask)
- sigaction(SIGUSR1, act, NULL)
25sa_handler vs. sa_sigaction
- We can get additional information about the
signal - void handler(int signo, siginfo_t info, void
context) - act.sa_flags SA_SIGINFO
- // fill sa_sigaction instead of sa_handler
- act.sa_sigaction handler
- Extra information contains, e.g., the source of
the signal (info-gtsi_code) - SI_USER user-created signal (with abort, kill,
etc.) - SI_TIMER a POSIXRTS timer expired
- etc.
26void handler(int sig, siginfo_t info, void
context) // handle SIGINT exit(EXIT_SUCCESS)
int main(int argc, char argv) int
n // set up SIGINT to call handler() for
() count 0 printf("tick\n") // we
sleep in a loop since it can be interrupted by
SIGINT n 5 do n sleep(n) while
(n gt 0) return EXIT_SUCCESS
- Windows users will sometimes press Ctrl-C (for
copy to clipboard), inadvertently killing a UNIX
process. - Lets change the SIGINT handler to kill the
process only if the user really means it! - i.e., presses Ctrl-C three times within a
5-second tick - And lets only count signals sent by the kernel
(based on keyboard input) - info-gtsi_code SI_KERNEL
27void handler(int sig, siginfo_t info, void
context) // handle SIGINT exit(EXIT_SUCCESS)
int main(int argc, char argv) int
n // set up SIGINT to call handler() for
() count 0 printf("tick\n") // we
sleep in a loop since it can be interrupted by
SIGINT n 5 do n sleep(n) while
(n gt 0) return EXIT_SUCCESS
int count 0
void handler(int sig, siginfo_t info, void
context)
// handle SIGINT if (info-gtsi_code SI_KERNEL
count gt 3) printf("Exiting by user's
request\n") exit(EXIT_SUCCESS)
int main(int argc, char argv) int n
struct sigaction act act.sa_flags
SA_SIGINFO act.sa_sigaction
handler sigemptyset(act.sa_mask) sigaction(SI
GINT, act, NULL)
for () count 0 printf("tick\n") n
5 // sleep in a loop since it can be
interrupted by SIGINT do n sleep(n)
while (n gt 0) return EXIT_SUCCESS
28pause(), wait()
29pause()
- Waits for any signal that is not blocked/ignored
- But if a signal is generated before pause() is
called, pause() will never see it - If we use the sigmask to block the signal until
pause() is called, it will be queued until we
remove it - However, pause() will just sit there waiting for
the signal that is blocked it will never check
the queue - In summary pause() only returns if called before
the signal is generated!
30sigwait()
- Takes as parameter a sigset corresponding to
which signals it should wait for - You should block the signals first
- sigwait() will remove a signal from the queue
that is in its sigset - Must also pass a pointer to an integer for it to
store signal that was removed - sigwait(sigset_t set, int signo)
31Counting signals
include ltstdio.hgt include ltstdlib.hgt include
ltunistd.hgt include ltsys/types.hgt include
ltsignal.hgt int main(int argc, char
argv) int signalcount 0 // block
SIGUSR1 and SIGUSR2 printf("waiting for
signals\n") for () // wait for a signal
instead of sleeping sleep(100) signalcount
printf("signals so far d\n",
signalcount) return EXIT_SUCCESS
32- Use sigwait() to count how many times a process
receives SIGUSR1 or SIGUSR2 - Dont forget to block them first!
include ltstdio.hgt include ltstdlib.hgt include
ltunistd.hgt include ltsys/types.hgt include
ltsignal.hgt int main(int argc, char
argv) int signalcount 0 // block
SIGUSR1 and SIGUSR2 printf("waiting for
signals\n") for () // wait for a signal
instead of sleeping sleep(100) signalcount
printf("signals so far d\n",
signalcount) return EXIT_SUCCESS
33include ltstdio.hgt include ltstdlib.hgt include
ltunistd.hgt include ltsys/types.hgt include
ltsignal.hgt int main(int argc, char argv)
include ltstdio.hgt include ltstdlib.hgt include
ltunistd.hgt include ltsys/types.hgt include
ltsignal.hgt int main(int argc, char
argv) int signalcount 0 // block
SIGUSR1 and SIGUSR2 printf("waiting for
signals\n") for () // wait for a signal
instead of sleeping sleep(100) signalcount
printf("signals so far d\n",
signalcount) return EXIT_SUCCESS
int signalcount 0 sigset_t sigset int
signo // block SIGUSR1 and SIGUSR2 sigemptyset
(sigset) sigaddset(sigset, SIGUSR1) sigaddse
t(sigset, SIGUSR2) sigprocmask(SIG_BLOCK,
sigset, NULL)
printf("waiting for signals\n") for ()
if (sigwait(sigset, signo) -1)
perror("Failed to wait using
sigwait") return EXIT_FAILURE
signalcount printf("signals so far
d\n", signalcount) return EXIT_SUCCESS
34POSIX TMR Timers
35POSIXTMR timers
- They are in charge of
- Sending the SIGALRM signal to the process
- If we set up a signal handler for SIGALRM, we
have a programmable timer! - Signals sent for timers or interrupts need to be
unblocked for the thread that will be receiving
them!!!
36Memory
37Memory
- Contiguous allocation and compaction
- Paging and page replacement algorithms
38Contiguous Allocation
- Memory is allocated in monolithic segments or
blocks - Public enemy 1 external fragmentation
- We can solve this by periodically rearranging the
contents of memory
39Compaction
- After numerous malloc() and free() calls, our
memory will have many holes - Total free memory is much greater than that of
any contiguous chunk - We can compact our allocated memory
- Shift all allocations to one end of memory, and
all holes to the other end - Temporarily eliminates of external fragmentation
40Compaction (example)
- Lucky that A fit in there! To be sure that there
is enough space, we may want to compact at (d),
(e), or (f) - Unfortunately, compaction is problematic
- It is very costly. How much, exactly?
- How else can we eliminate external fragmentation?
41Summary Paging
- Divide memory into pages of equal size
- We dont need to assign contiguous chunks
- Internal fragmentation can only occur on the last
page assigned to a process - External fragmentation cannot occur at all
- Need to map contiguous logical memory addresses
to disjoint pages
42Summary Virtual Memory
- RAM is expensive (but fast), disk is cheap (but
slow) - Need to find a way to use the cheaper memory
- Store memory that isnt frequently used on disk
- Swap pages between disk and memory as needed
- Treat main memory as a cache for pages on disk
43Page Replacement
- We may not have enough space in physical memory
for all pages of every process at the same time. - But which pages shall we keep?
- Use the history of page accesses to decide
- Also useful to know the dirty pages
44Page Replacement Strategies
- It takes two disk operations to replace a dirty
page, so - Keep track of dirty bits, attempt to replace
clean pages first - Write dirty pages to disk during idle disk time
- We try to approximate the optimal strategy but
can seldom achieve it, because we dont know what
order a process will use its pages. - Best we can do is run a program multiple times,
and track which pages it accesses
45Page Replacement Algorithms
- Optimal last page to be used in the future is
removed first - FIFO First in First Out
- Based on time the page has spent in main memory
- LRU Least Recently Used
- Locality of reference principle again
- MRU most recently used removed first
- When would this be useful?
- LFU Least Frequently Used
- Replace the page that is used least often
46Example
- Physical memory size 4 pages
- Pages are loaded on demand
- Access history 0 1 2 3 4 0 1 2 3 4
- Which algorithm does best here?
- Access history 0 1 2 3 4 4 3 2 1 0
- And here?