Wednesday, June 10, 2009
Friday, April 17, 2009
Monday, March 2, 2009
FD_xxx API
typedef unsigned int u_int;
typedef u_int SOCKET;
typedef struct fd_set {
u_int fd_count;
SOCKET fd_array[FD_SETSIZE];
} fd_set;
#define FD_CLR(fd, set) \
do \
{ \
u_int __i; \
for (__i = 0; __i < ((fd_set *)(set))->fd_count; __i++) \
{ \
if (((fd_set *)(set))->fd_array[__i] == (fd)) \
{ \
while (__i < ((fd_set *)(set))->fd_count - 1) \
{ \
((fd_set*)(set))->fd_array[__i] = ((fd_set*)(set))->fd_array[__i + 1]; \
__i++; \
} \
((fd_set*)(set))->fd_count--; \
break; \
} \
} \
} while (0)
#define FD_SET(fd, set) \
do \
{ \
u_int __i; \
for (__i = 0; __i < ((fd_set *)(set))->fd_count; __i++) \
{ \
if (((fd_set *)(set))->fd_array[__i] == (fd)) \
{ \
break; \
} \
} \
if (__i == ((fd_set *)(set))->fd_count) \
{ \
if (((fd_set *)(set))->fd_count < FD_SETSIZE) \
{ \
((fd_set *)(set))->fd_array[__i] = (fd); \
((fd_set *)(set))->fd_count++; \
} \
} \
} while(0)
#define FD_ZERO(set) (((fd_set *)(set))->fd_count = 0)
#define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set *)(set))
Thursday, February 26, 2009
Handling SIGCHLD Signals
The purpose of the zombie state is to maintain information about the child for the parent to fetch at some later time. This information includes the process ID of the child, its termination status, and information on the resource utilization of the child (CPU time, memory, etc.). If a process terminates, and that process has children in the zombie state, the parent process ID of all the zombie children is set to 1 (the init process), which will inherit the children and clean them up (i.e., init will wait for them, which removes the zombie). Some Unix systems show the COMMAND column for a zombie process as <defunct>.
Handling Zombies
Obviously we do not want to leave zombies around. They take up space in the kernel and eventually we can run out of processes. Whenever we fork children, we must wait for them to prevent them from becoming zombies. To do this, we establish a signal handler to catch SIGCHLD, and within the handler, we call wait.
We establish the signal handler by adding the function call
Signal (SIGCHLD, sig_chld);
1 #include "unp.h"
2 void
3 sig_chld(int signo)
4 {
5 pid_t pid;
6 int stat;
7 pid = wait(&stat);
8 printf("child %d terminated\", pid);
9 return;
10 }
Warning: Calling standard I/O functions such as printf in a signal handler is not recommended. We call printf here as a diagnostic tool to see when the child terminates.
Under System V and Unix 98, the child of a process does not become a zombie if the process sets the disposition of SIGCHLD to SIG_IGN. Unfortunately, this works only under System V and Unix 98. POSIX explicitly states that this behavior is unspecified. The portable way to handle zombies is to catch SIGCHLD and call wait or waitpid.
#include "unp.h"
int
main(int argc, char **argv)
{
int listenfd, connfd;
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
void sig_chld(int);
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);
Signal(SIGCHLD, sig_chld);
for ( ; ; ) {
clilen = sizeof(cliaddr);
if ( (connfd = accept(listenfd, (SA *) &cliaddr, &clilen)) < 0) {
if (errno == EINTR)
continue; /* back to for() */
else
err_sys("accept error");
}
if ( (childpid = Fork()) == 0) { /* child process */
Close(listenfd); /* close listening socket */
str_echo(connfd); /* process the request */
exit(0);
}
Close(connfd); /* parent closes connected socket */
}
}
solaris % tcpserv02 & // start server in background
[2] 16939
solaris % tcpcli01 127.0.0.1 // then start client in foreground
hi there // we type this
hi there // and this is echoed
^D // we type our EOF character
child 16942 terminated // output by printf in signal handler
accept error: Interrupted system call // main function aborts
The sequence of steps is as follows:
We terminate the client by typing our EOF character. The client TCP sends a FIN to the server and the server responds with an ACK.
The receipt of the FIN delivers an EOF to the child's pending readline. The child terminates.
The parent is blocked in its call to accept when the SIGCHLD signal is delivered. The sig_chld function executes (our signal handler), wait fetches the child's PID and termination status, and printf is called from the signal handler. The signal handler returns.
Since the signal was caught by the parent while the parent was blocked in a slow system call (accept), the kernel causes the accept to return an error of EINTR (interrupted system call). The parent does not handle this error, so it aborts.
The purpose of this example is to show that when writing network programs that catch signals, we must be cognizant of interrupted system calls, and we must handle them. In this specific example, running under Solaris 9, the signal function provided in the standard C library does not cause an interrupted system call to be automatically restarted by the kernel. That is, the SA_RESTART flag that we set is not set by the signal function in the system library. Some other systems automatically restart the interrupted system call. If we run the same example under 4.4BSD, using its library version of the signal function, the kernel restarts the interrupted system call and accept does not return an error. To handle this potential problem between different operating systems is one reason we define our own version of the signal function that we use throughout the text.
As part of the coding conventions used in this text, we always code an explicit return in our signal handlers, even though falling off the end of the function does the same thing for a function returning void. When reading the code, the unnecessary return statement acts as a reminder that the return may interrupt a system call.
Handling Interrupted System Calls
We used the term "slow system call" to describe accept, and we use this term for any system call that can block forever. That is, the system call need never return. Most networking functions fall into this category. For example, there is no guarantee that a server's call to accept will ever return, if there are no clients that will connect to the server. Similarly, our server's call to read will never return if the client never sends a line for the server to echo. Other examples of slow system calls are reads and writes of pipes and terminal devices. A notable exception is disk I/O, which usually returns to the caller (assuming no catastrophic hardware failure).
The basic rule that applies here is that when a process is blocked in a slow system call and the process catches a signal and the signal handler returns, the system call can return an error of EINTR. Some kernels automatically restart some interrupted system calls. For portability, when we write a program that catches signals (most concurrent servers catch SIGCHLD), we must be prepared for slow system calls to return EINTR. Portability problems are caused by the qualifiers "can" and "some," which were used earlier, and the fact that support for the POSIX SA_RESTART flag is optional. Even if an implementation supports the SA_RESTART flag, not all interrupted system calls may automatically be restarted. Most Berkeley-derived implementations, for example, never automatically restart select, and some of these implementations never restart accept or recvfrom.
To handle an interrupted accept, we change the call to accept, the beginning of the for loop, to the following:
for ( ; ; ) {
clilen = sizeof (cliaddr);
if ( (connfd = accept (listenfd, (SA *) &cliaddr, &clilen)) < 0) {
if (errno == EINTR)
continue; /* back to for () */
else
err_sys ("accept error");
}
Notice that we call accept and not our wrapper function Accept, since we must handle the failure of the function ourselves.
What we are doing in this piece of code is restarting the interrupted system call. This is fine for accept, along with functions such as read, write, select, and open. But there is one function that we cannot restart: connect. If this function returns EINTR, we cannot call it again, as doing so will return an immediate error. When connect is interrupted by a caught signal and is not automatically restarted, we must call select to wait for the connection to complete.
POSIX Signal Handling
A signal is a notification to a process that an event has occurred. Signals are sometimes called software interrupts. Signals usually occur asynchronously. By this we mean that a process doesn't know ahead of time exactly when a signal will occur.
Signals can be sent
-
By one process to another process (or to itself)
-
By the kernel to a process
The SIGCHLD signal that we described at the end of the previous section is one that is sent by the kernel whenever a process terminates, to the parent of the terminating process.
Every signal has a disposition, which is also called the action associated with the signal. We set the disposition of a signal by calling the sigaction function (described shortly) and we have three choices for the disposition:
-
We can provide a function that is called whenever a specific signal occurs. This function is called a signal handler and this action is called catching a signal. The two signals SIGKILL and SIGSTOP cannot be caught. Our function is called with a single integer argument that is the signal number and the function returns nothing. Its function prototype is therefore
void handler (int signo);
For most signals, calling sigaction and specifying a function to be called when the signal occurs is all that is required to catch a signal. But we will see later that a few signals, SIGIO, SIGPOLL, and SIGURG, all require additional actions on the part of the process to catch the signal.
We can ignore a signal by setting its disposition to SIG_IGN. The two signals SIGKILL and SIGSTOP cannot be ignored.
We can set the default disposition for a signal by setting its disposition to SIG_DFL. The default is normally to terminate a process on receipt of a signal, with certain signals also generating a core image of the process in its current working directory. There are a few signals whose default disposition is to be ignored: SIGCHLD and SIGURG (sent on the arrival of out-of-band data) are two that we will encounter in this text.
signal Function
The POSIX way to establish the disposition of a signal is to call the sigaction function. This gets complicated, however, as one argument to the function is a structure that we must allocate and fill in. An easier way to set the disposition of a signal is to call the signal function. The first argument is the signal name and the second argument is either a pointer to a function or one of the constants SIG_IGN or SIG_DFL. But, signal is an historical function that predates POSIX. Different implementations provide different signal semantics when it is called, providing backward compatibility, whereas POSIX explicitly spells out the semantics when sigaction is called. The solution is to define our own function named signal that just calls the POSIX sigaction function. This provides a simple interface with the desired POSIX semantics. We include this function in our own library, along with our err_XXX functions and our wrapper functions, for example, that we specify when building any of our programs in this text.
1 #include "unp.h"
2 Sigfunc *
3 signal (int signo, Sigfunc *func)
4 {
5 struct sigaction act, oact;
6 act.sa_handler = func;
7 sigemptyset (&act.sa_mask);
8 act.sa_flags = 0;
9 if (signo == SIGALRM) {
10 #ifdef SA_INTERRUPT
11 act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
12 #endif
13 } else {
14 #ifdef SA_RESTART
15 act.sa_flags |= SA_RESTART; /* SVR4, 4.4BSD */
16 #endif
17 }
18 if (sigaction (signo, &act, &oact) < 0)
19 return (SIG_ERR);
20 return (oact.sa_handler);
21 }
Sigfunc *
Signal(int signo, Sigfunc *func) /* for our signal() function */
{
Sigfunc *sigfunc;
if ( (sigfunc = signal(signo, func)) == SIG_ERR)
err_sys("signal error");
return(sigfunc);
}
#define SIG_DFL (void (*)(int))0
#define SIG_IGN (void (*)(int))1
#define SIG_ERR (void (*)(int))-1
Simplify function prototype using typedef
2–3 The normal function prototype for signal is complicated by the level of nested parentheses.
void (*signal (int signo, void (*func) (int))) (int);
To simplify this, we define the Sigfunc type in our unp.h header as
typedef void Sigfunc(int);
stating that signal handlers are functions with an integer argument and the function returns nothing (void). The function prototype then becomes
Sigfunc *signal (int signo, Sigfunc *func);
A pointer to a signal handling function is the second argument to the function, as well as the return value from the function.
Set handler
6 The sa_handler member of the sigaction structure is set to the func argument.
Set signal mask for handler
7 POSIX allows us to specify a set of signals that will be blocked when our signal handler is called. Any signal that is blocked cannot be delivered to a process. We set the sa_mask member to the empty set, which means that no additional signals will be blocked while our signal handler is running. POSIX guarantees that the signal being caught is always blocked while its handler is executing.
Set SA_RESTART flag
8–17 SA_RESTART is an optional flag. When the flag is set, a system call interrupted by this signal will be automatically restarted by the kernel. (We will talk more about interrupted system calls in the next section when we continue our example.) If the signal being caught is not SIGALRM, we specify the SA_RESTART flag, if defined. (The reason for making a special case for SIGALRM is that the purpose of generating this signal is normally to place a timeout on an I/O operation, in which case, we want the blocked system call to be interrupted by the signal.) Some older systems, notably SunOS 4.x, automatically restart an interrupted system call by default and then define the complement of this flag as SA_INTERRUPT. If this flag is defined, we set it if the signal being caught is SIGALRM.
Call sigaction
18–20 We call sigaction and then return the old action for the signal as the return value of the signal function.
POSIX Signal Semantics
We summarize the following points about signal handling on a POSIX-compliant system:
Once a signal handler is installed, it remains installed. (Older systems removed the signal handler each time it was executed.)
While a signal handler is executing, the signal being delivered is blocked. Furthermore, any additional signals that were specified in the sa_mask signal set passed to sigaction when the handler was installed are also blocked. We set sa_mask to the empty set, meaning no additional signals are blocked other than the signal being caught.
If a signal is generated one or more times while it is blocked, it is normally delivered only one time after the signal is unblocked. That is, by default, Unix signals are not queued. We will see an example of this in the next section. The POSIX real-time standard, 1003.1b, defines some reliable signals that are queued, but we do not use them in this text.
It is possible to selectively block and unblock a set of signals using the sigprocmask function. This lets us protect a critical region of code by preventing certain signals from being caught while that region of code is executing.
a·pos·tate ~ ap·ti·tude
a·pos·tate〔, │〕 n. 배교자, 배신자;변절자, 탈당자
━ a. 배교의;배신[변절]의
ap·o·stat·ic, -i·cal[] a.
Because he switched from one party to another, his former friends shunned him as an apostate.
a·pos·ta·sy〔│〕 n. (pl. -sies) [U.C] 배교(背敎), 배신(背信);변절, 탈당
a charge of apostasy
a·poth·e·car·y〔│〕 n. (pl.-car·ies) 《미·고어》 약종상, 약제사(druggist);《미》 약국
In the apothecaries' weight, twelve ounces equal one pound.
ap·o·thegm〔〕 n. 경구, 격언
Proverbs are apthegms that have become familiar sayings.
a·poth·e·o·sis〔, │〕 n. (pl. -ses[])
1 [U.C] (사람을) 신으로 모심, 신격화;신성시, 숭배;신격화된 것
2 이상(理想)의 상(像), 극치;권화(權化) 《of》
3 (사람·물건의) 승천(昇天)
The Oriental in Bangkok is the apotheosis of the grand hotel.
The apotheosis of a Roman emperor was designed to insure his eternal greatness.
ap·pa·ri·tion〔〕 n.
1 유령, 망령, 환영
2 경이적인[불가사의한] 것
3 (모습 등의) 출현
4【천문】 (혜성 등의, 특히 정기적인) 출현
▷ appar v.
It could be some sort of a hallucination in the mind of the fantasy-prone person, or there could be some apparition that's explained by physics here.
I've never seen the apparition of the little girl, but she does pull a little prank of sleeping on this bed behind us, and she leaves the impression of her body on the bed.
Hamlet was uncertain about the identity of the apparition that had appeared and spoken to him.
ap·pease〔〕〔OF 「평화(peace)롭게 하다」의 뜻에서〕 vt.
1 <사람을> 달래다;<싸움을> 진정시키다;<노염·슬픔을> 가라앉히다
The sight appeased his anger. 그 광경을 보고 그는 화가 가라앉았다.
《appease+목+전+명》 appease a person by kindness[with a present] 친절[선물]로 …을 달래다
2 <갈증을> 풀어 주다;<식욕·호기심 등을> 충족시키다
appease one’s hunger[curiosity] 허기[호기심]를 채우다
3 (절개를 굽혀) 양보하다
appease·ment n. 위무, 진정, 완화, 양보; 유화 정책 ap·pas·er n.
Gandhi was accused by some of trying to appease both factions of the electorate.
We have discovered that, when we try to appease our enemies, they make additional demands.
ap·pel·la·tion〔〕 n. 명칭, 통칭, 호칭, 명명, epithet(나쁜의미)
He earned the appellation `rebel priest.'
He was amazed when the witches hailed him with his correct appellation.
ap·pend〔〕 vt.
1 덧붙이다, 부가[추가]하다, 부록에 달다 《to》
I append Mr. A’s letter herewith. 여기에 A씨의 편지를 첨부합니다.
《append+목+전+명》 append a label to a trunk 트렁크에 꼬리표를 붙이다
2 <펜던트 등을> 달다, 매달다 《to》
3 <서명·도장을> (문서에) 쓰다, 찍다(affix) 《to》
Violet appended a note at the end of the letter.
It was a relief that his real name hadn't been appended to the manuscript.
I shall append this chart to my report.
ap·praise〔〕 vt. <물건·재산을> 값매기다, 견적[감정]하다;<사람·능력을> 평가하다(⇒ estimate [유의어]);…의 (치수·중량·품질 등을) 평가[계산]하다
I had an expert appraise the house beforehand. 나는 사전에 전문가에게 그 가옥을 평가시켰다.
《appraise+목+전+명》 appraise property[land] at fifty thousand dollars 재산[토지]을 5만 달러로 평가하다
appraise property for taxation 과세하기 위해 재산을 감정하다
ap·pris·ee n. appraise·ment n. ap·pris·ive a.
▷ apprisal n.
It is difficult to appraise the value of old paintings; it is easier to call them priceless.
ap·por·tion〔〕 vt. 배분하다, 할당하다 《to》
《apportion+목+전+명》 apportion something between[among] persons 물건을 사람들에게 배분하다
apportion·a·ble a. apportion·er n.
I'll apportion each of you different task.
ap·pre·hend〔prihnd〕〔L 「파악하다」의 뜻에서〕 vt.
1 《문어》 <범인을> 체포하다 《★ catch, seize, arrest가 일반적》
The thief was apprehended. 도둑은 체포되었다.
2 <의미를> 파악하다, 이해하다, 깨닫다
《apprehend+that 절》 I apprehended that the situation was serious. 사태가 심각함을 깨달았다.
3 우려하다, 염려하다(fear)
It is apprehended that ... …할 우려가 있다
There is nothing to apprehend. 아무것도 염려할 게 없다.
━ vi.
1 깨닫다, 이해되다
2 걱정되다, 염려되다
apprehend·er n.
▷ apprehnsion n.;apprehnsive a.
The police will apprehend the culprit before long.
ap·pre·hen·sive〔〕 a.
1 우려하는, 염려하는 《of, for, about》
2 이해가 빠른, 총명한(intelligent)
3 알아채고[깨닫고] (있는) 《of》
be apprehensive for (a person’s safety) (…의 안부)를 걱정하다
His apprehensive glances at the people who were walking in the street revealed his nervousness.
People are still terribly apprehensive about the future.
ap·prise1, ap·prize1〔〕 vt. 《문어》 <사람에게 …을> 통지하다(inform), 알리다 《of》
When he was apprised of the dangerous weather conditions, he decided to postpone his trip.
Have customers been fully apprised of the advantages?
We must apprise them of the dangers that may be involved.
ap·pur·te·nance〔〕 n.
1 [보통 pl.] 부속물;[pl.] 기계 장치
2【법】 종물(從物)
a house and all its appurtenances
He bought the estate and all its appurtenances.
1 (…에의) 경향, 습성 《to》;(…하는) 기질, 성질 《for doing, to do》
2 (…의) 소질, 재능, 능력, 수완;(학문·공부의) 총명함, 지력 《for, in》
3 적성, 어울림(fitness) 《for》
have an aptitude for …에 소질[재능]이 있다
have an aptitude to vices (악)에 물들기 쉽다
ap·ti·tu·di·nal[│] a. p·ti·tdi·nal·ly[] ad.
▷ pt a.
SAT [Scholastic Aptitude Test]
The counselor gave him an aptitude test before advising him about the career he should follow.
An aptitude for computing is beneficial for students taking this degree.
e·pit·o·me〔〕〔Gk 「요약하다」의 뜻에서〕 n.
1 발췌(拔萃), 개요;대요, 개략
2 《비유》 (…의) 축도(縮圖)
man, the world’s epitome 세계의 축도인 인간
in epitome 요약된 형태로;축도화되어
Maureen was the epitome of sophistication.
prank1
1 농담, 희롱, (짓궂은) 장난(mischief);간계(奸計)
2 (기계 등의) 부정확한 작동;(동물의) 익살스런 동작
prank2
prank2 vt. , vi. 화려하게 차려 입다 《with》, 모양내다 《out, up》
play pranks on[upon]
…을 조롱하다
Stop playing pranks on me.
a harmless prank
The orchard is now pranked with blossoms.
Don´t make such a fuss all the time about kids´ pranks.
hal·lu·ci·na·tion〔〕 n. [U.C] 환각(cf. ILLUSION); 환상;잘못된 생각[신념, 신앙, 인상];곡두, 망상(delusion), 착각
suffer from hallucinations 환각에 시달리다
be under hallucination 착각하고 있다
hallucination·al a.hal·lu·ci·na·tive[, │] a.
The drug induces hallucinations at high doses.
shun
1 피하다, 멀리하다
2 《고어》 면하다
3 《고어》 막다
'shun
'shun〔〕〔attention에서〕 int. 차렷
acquaintances politely shunned by one another.
shun society.
He tried to shun contact with us.
He is kept at a respectful distance. or He is politely shunned by everybody.
The electronics-parts sector is being shunned by investors, who fear computer.
e·lec·tor·ate〔〕 n.
1 [the electorate;집합적] 선거민 (전체), 유권자 (전원)
2【역사】 (신성 로마 제국의) 선거후(侯)의 지위[관할, 영토]
the power of the unwashed electorate
He has the backing of almost a quarter of the electorate.
reb·el〔〕〔L 「전쟁을 다시 하다」의 뜻에서〕 n.
1 반역자, 반도, 반항자 《against, to》
2 [종종 Rebel] 《미》 반란군 병사 《남북 전쟁 때의 남군 병사》;[종종 Rebel] 《미·구어》 남부 백인
━ a. 반역의
the rebel army 반란군
━ [] vi. (rebelled;rebel·ling)
1 모반[반역]하다, 반란을 일으키다 《against》;(권위·관습 등에) 반대하다, 반항하다 《against》
rebel against all authority 모든 권위에 대항하다
2 화합하지 않다 《with》;반감을 가지다, 반발하다, 몸서리치다 《against, at》
《rebel+전+명》 My mind rebels at the thought. 그것을 생각하면 오싹해진다.
rebel·lke a.
▷ rebllion n.;rebllious a.
Sudan's government says it is ready to accept a proposed peace deal with Darfur rebels, but rebel negotiators are holding out, saying the draft agreement still does not meet their key demands.
Sri Lanka has stopped bombing Tamil rebel targets and re-opened borders with rebel territory.