<html>

<head><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- MyFirstUnitAd -->
<ins class="adsbygoogle"
     style="display:inline-block;width:970px;height:250px"
     data-ad-client="ca-pub-5778386704669218"
     data-ad-slot="1503492166"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>

<meta http-equiv="Content-Language" content="en-ca">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 6.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>whatevergoes</title>
<style>
<!--
	table td.head{ 
		background-color: #3a6ba5;
		border: 1px #000000 solid;
		font-family: Verdana;
		font-weight: bold;
		font-size: 14px;
		color: #f79c19;
		padding: 6px;
	}

	table td.body{ 
		border-bottom: 1px #6699CC dotted;
		text-align: left;
		font-family: Verdana, sans-serif, Arial;
		font-weight: normal;
		font-size: 14px;
		color: #3A6BA5;
		background-color: #fafafa;
		padding: 6px;
	}
	
 li.MsoNormal
	{mso-style-parent:"";
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:"Times New Roman";
	margin-left:0cm; margin-right:0cm; margin-top:0cm}
-->
</style>
</head>

<body>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#FF0000" size="6"><b>
<span lang="en-ca">Whatever Goes...</span></b></font></p>
<pre><span lang="en-ca">		<b><font color="#FF0000" size="4"><a name="feof"></a>The evil of feof!!!</font></b></span></pre>
<pre><span lang="en-ca">	&quot;feof&quot; tortures me for long time! Because I simply don't understand what I read! Do you see the stupid bug following?</span></pre>
<pre><span lang="en-ca">What do you know the meaning of &quot;feof&quot;? It only gives the true value when you TRY to PASS the end of file, not BEFORE! I think,</span></pre>
<pre><span lang="en-ca">probably very few people will make this kind of stupid mistake like me. However, I just post it here for a memorandom!</span></pre>
<pre>&nbsp;</pre>
<pre>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

char* fileName=&quot;yourFile.txt&quot;;
const int BufferSize=20;
char buffer[BufferSize+1];

int main()
{
	FILE* stream;
	char ch;
	char* ptr;
	int counter=0;
	if ((stream=fopen(fileName, &quot;r&quot;))==NULL)
	{
		printf(&quot;Cannot open file %s\n&quot;, fileName);
		exit(1);
	}
	while (!feof(stream))
	{
		ch=fgetc(stream);
		buffer[counter++]=ch;
		if (counter==BufferSize)
		{
			buffer[counter]='\0';
			printf(&quot;now output string of length %d : %s\n&quot;, BufferSize, buffer);
			counter=0;
		}
	}
	if (counter!=0)
	{
		buffer[counter]='\0';
		printf(&quot;now output last line of length %d : %s\n&quot;, counter, buffer);
	}
	printf(&quot;however this is not end!!! What I mean is that there is a big bug&quot;);
	printf(&quot; which I always ignore: There is an evil character at end of this line&quot;);
	printf(&quot; let me show you in ASCII number, and pay attention to last one!\n&quot;);
	ptr=buffer;
	while (*ptr!='\0')
	{
		printf(&quot;char:%c = ASCII: %d\n&quot;, *ptr, *ptr);
		ptr++;
	}
	return 0;
}


</pre>
<pre><font color="#0000FF" size="3"><span lang="en-ca">If you don't see any problem, just look at the running result below:</span></font></pre>

<pre><span lang="en-ca">now output string of length 20 : The feof routine (im
now output string of length 20 : plemented both as a
now output string of length 20 : function and as a ma
now output string of length 20 : cro) determines whet
now output string of length 20 : her the end of strea
now output string of length 20 : m has been reached.
now output string of length 20 : When end of file is
now output string of length 20 : reached, read operat
now output string of length 20 : ions return an end-o
now output string of length 20 : f-file indicator unt
now output string of length 20 : il the stream is clo
now output string of length 20 : sed or until rewind,
now output string of length 20 : fsetpos, fseek, or
now output string of length 20 : clearerr is called a
now output last line of length 10 : gainst it&#63733;
however this is not end!!! What I mean is that there is a big bug which I always ignore: There is an
evil character at end of this line let me show you in ASCII number, and pay attention to last one!
char:g = ASCII: 103
char:a = ASCII: 97
char:i = ASCII: 105
char:n = ASCII: 110
char:s = ASCII: 115
char:t = ASCII: 116
char: = ASCII: 32
char:i = ASCII: 105
char:t = ASCII: 116
char:&#63733; = ASCII: -1
Press any key to continue</span></pre>
<pre><font color="#FF0000">***********************************</font></pre>
<pre><font color="#FF0000">After quite a few years later, I take a look at what I was doing before. The problem can be fixed by using </font></pre>
<pre><font color="#FF0000">if ((ch=fgetc(stream))!=EOF) break;</font></pre>
<pre><font color="#FF0000">The &quot;feof&quot; is not a </font><b><font color="#0000FF">&quot;peek&quot;</font></b><font color="#FF0000"> operation, but you have to do the actual fgetc or fread. There is no </font><b><font color="#0000FF">&quot;peek&quot;</font></b><font color="#FF0000">. i.e. no reading </font></pre>
<pre><font color="#FF0000">but only testing. No such thing at all!</font></pre>
<pre><font color="#FF0000">*************************************</font></pre>
<pre>&nbsp;</pre>
<pre>	</pre>
<pre><![if !supportLineBreakNewLine]><![endif]>
</pre>

<p><span lang="en-ca">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<b><font color="#FF0000"><a name="latency"></a>The latency of disk head moves...</font></b></span></p>

<p>
      <span lang="en-ca"><![if !supportLineBreakNewLine]>
      So, everybody who already has taken computer architecture course knows 
      that the<![endif]><![if !supportLineBreakNewLine]>
      <a href="elevator.htm">average latency time</a> for
      <a href="elevator1.htm">disk arm to move </a>to the target track is 1/3 of 
      time it moves across all tracks. But how to calculate this? Honestly I 
      don't know. I write a simple program to simulate and convince myself. 
      However, there is one pre-condition for all kinds of &quot;average waiting 
      time&quot; problems no matter whether the waiting elements are processes or 
      tasks or threads or whatever. The length of queue must be stable otherwise 
      there is no average waiting time at all.&nbsp; Just imagine the queue is 
      continuing to increase as the output is much slower than input. Can you 
      predict the average waiting time? Increasing to infinite?&nbsp; That is 
      why I write the second version to test under different the incoming rate. 
      The result is exactly 1/3 if the tasks are sparse and few.<![endif]></span></p>

<p><span lang="en-ca">This is a very simple question. However, as you know, as I 
have little knowledge of integral,&nbsp; (amazing?) it becomes a very difficult 
problem for me. </span></p>

<p><span lang="en-ca"><![if !supportLineBreakNewLine]>
      After lunch I visit Mr. Zhu and understand the way of integral. The 
&quot;latency&quot; has nothing to do with &quot;waiting time&quot;. They are completely different 
things!!! Latency is simply the time needed to reach the point by moving disk 
head. We simply don't have to consider the waiting time for each task. <![endif]>
</span></p>

<p><span lang="en-ca"><![if !supportLineBreakNewLine]>
      proof:<![endif]></span></p>

<table border="3" cellpadding="0" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%" id="AutoNumber1">
  <tr>
    <td bgcolor="#FF0000">&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td bgcolor="#FF0000">&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td bgcolor="#00FFFF">&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td bgcolor="#FF0000">&nbsp;</td>
  </tr>
</table>

<p><span lang="en-ca"><![if !supportLineBreakNewLine]>
      center&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
edge<![endif]></span><![if !supportLineBreakNewLine]><![endif]></p>

<p><span lang="en-ca"><![if !supportLineBreakNewLine]>
      |---------------n tracks-------------|<![endif]></span></p>

<p><span lang="en-ca"><![if !supportLineBreakNewLine]>
      |-----------------------------------------------------N tracks 
------------------------------------------------|<![endif]></span></p>

<p><span lang="en-ca"><![if !supportLineBreakNewLine]>
      1. Assume disk head is at position with h% number of tracks away from 
center of disk. That is, if the track number is N, disk head is at a position 
with n tracks away from center. And h=n/N %.<![endif]></span></p>

<p><span lang="en-ca"><![if !supportLineBreakNewLine]>
      2. For any task in a position of x% of total tracks away from center, the 
disk head will take abs(h-x) of time<![endif]></span></p>

<p><span lang="en-ca"><![if !supportLineBreakNewLine]>
      to reach it. The time of abs(h-x) is actually the major factor of latency.<![endif]></span></p>

<p><span lang="en-ca"><![if !supportLineBreakNewLine]>
      3. Since the task is equally likely to be any position in the disk, we can 
use integral to calculate the latency<![endif]></span></p>

<p><span lang="en-ca">as following:&nbsp; (Let's define S(exp, upper, lower)dx 
as integral(S) for expression(exp) from &quot;lower&quot; to &quot;upper&quot;)</span></p>

<p><span lang="en-ca">Latency(h) = S(h-x, 0, h)dx + S(x-h, h, 1)dx = h^2 - h 
+1/2</span></p>

<p><span lang="en-ca">4. Now we want to integral for disk head along all tracks:</span></p>

<p><span lang="en-ca">Latency in average = S(h^2 -h +1/2, 0, 1) = 1/3</span></p>

<p>&nbsp;</p>

<p><font color="#FF0000"><![if !supportLineBreakNewLine]>
      <b>Minimize DFA</b><![endif]></font></p>

<p><a name="minDFA"></a></p>

<p><![if !supportLineBreakNewLine]>
      <![endif]>&gt; Blum(a German Prof.) Algorithm like Hopcroft Alg. :<br>
&gt;<br>
&gt; DFA--&gt;DFA(min)<br>
&gt; Input: reduced DFA M = (Q,Sigma, delta, q0,F).<br>
&gt; Output: minimal DFA M´ = (Q´, Sigma, delta´,qo´,F´).<br>
&gt; Method:<br>
&gt;&nbsp;&nbsp;&nbsp; (1)&nbsp; t:=2; Q1:= F; Q2 := Q\F.<br>
&gt;&nbsp;&nbsp; (2)&nbsp; while there is i &lt;= t, a &lt;- Sigma<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with delta(Qi, a) /&lt;= Qj for all j &lt;= t<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.&nbsp; choose so one i &lt;= t, a &lt;-Sigma and j &lt;= t<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with delta(Qi, a) intersection Qj /= {}.<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.&nbsp; Q(t+1) := {q &lt;- Qi | delta (q, a) &lt;- Qj};<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Qi&nbsp; := Qi\ Q(t+1);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t := t+1<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; od.<br>
&gt;&nbsp; (3) Q´ : ={Q1,Q2,...,Qt};<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q0´ := [q0];<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F´:= {[q] &lt;-Q´ |q &lt;- F};<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delta´( [q],a) := [delta(q,a)]<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for all q &lt;-Q, a&lt;-Sigma.<br>
&gt;<br>
&nbsp;<![if !supportLineBreakNewLine]><![endif]></p>

<p><![if !supportLineBreakNewLine]>
      <![endif]>Fascinating!!<br>
Is this algorithm called Blum algorithm? I never heard aobut that. Maybe in<br>
North America, they are called in different names. Anyway, the notation of<br>
pseudo code puzzled me for a while and finally I thought I figured out,<br>
please verify if it is the idea:<br>
1. The first step is to separate DFA into two collections, one contains the<br>
final state F and the other one is its complement.<br>
2. Continual iterating with all collections to find any two collections A,B,<br>
such that for any particular sigma character 'a', NOT all the arches of&nbsp; 'a'<br>
from collection A goes to other collection B. (It means the states in<br>
collection A have some arches of 'a' pointing to other collection other than<br>
B. ) And we try to divide the collection A into two sub-collection such that<br>
the states in A with arches with label 'a'&nbsp; pointing to B is a new<br>
sub-collection&nbsp; C, and A - C is another collection.<br>
3. Finally we got our reduced DFA such that the final states is the<br>
collection of collections such that they contains original final state F.<br>
The transition functions, or delta, or arches, are such that the domain is<br>
the closure of states q, or those collections which contains q, and the<br>
range is the closure of state delta(q,a), in other words, the collections<br>
which contains state of<br>
delta(q,a).<br>
<br>
Is my understanding right?<br>
&nbsp;<![if !supportLineBreakNewLine]><![endif]></p>

<p><b><font color="#FF0000" size="4"><span lang="en-ca"><![if !supportLineBreakNewLine]>
      My miserable life in Concordia...<![endif]></span></font></b></p>

<pre>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;setjmp.h&gt;

typedef int Exception;

jmp_buf jumpBuf;

#define CourseNumber 4

#define E_chem205 1
#define E_comp326 2
#define E_comp444 3
#define E_stat250 4

char* courseName[CourseNumber]=
{
	&quot;chem205&quot;, &quot;comp326&quot;, &quot;comp444&quot;, &quot;stat250&quot;
};

typedef  void CourseFunc(void);


void chem205();
void comp326();
void comp444();
void stat250();

//function pointer array
CourseFunc* myCourse[CourseNumber]=
{
	chem205, comp326, comp444, stat250
};


int main()
{
	int week,course;
	Exception exp;
	//I have to suffer 13 weeks for a term
	for (week=0; week&lt;13; week++)
	{
		printf(&quot;****************\nnow it is week %d\n****************************\n&quot;, week+1);
		for (course=0; course&lt;CourseNumber; course++)
		{
			myCourse[course]();
			if ((exp=setjmp(jumpBuf))!=0)
			{
				if (exp==E_comp444)
				{
					printf(&quot;I don't believe you, just quit\n&quot;);
					exit(E_comp444);
				}
				else
				{
					printf(&quot;I know you are suffering from %s,&quot;, courseName[exp-1]);
					printf(&quot;you still have to hold on\n*************************\n&quot;);
					//do nothing but continue
				}
			}
			
		}
	}
	return 0;
}


//there is 80% chance, I would complain----throw an expception for protest
void chem205()
{
	if (rand()%100&lt;80)
	{
		printf(&quot;chemstry has too many compound name to memorize\n&quot;);
		printf(&quot;I want to throw an exception\n&quot;);
		longjmp(jumpBuf, E_chem205);
	}
	printf(&quot;I continue studying chem205\n&quot;);
}

//there is 60% chance, I would complain----throw an expception for protest
void stat250()
{
	if (rand()%100&lt;60)
	{
		printf(&quot;statistic has too many integral caculus\n&quot;);
		printf(&quot;I want to throw an exception\n&quot;);
		longjmp(jumpBuf, E_stat250);
	}
	printf(&quot;I continue studying stat250\n&quot;);
}

//there is 90% chance, I would complain----throw an expception for protest
void comp326()
{
	if (rand()%100&lt;90)
	{
		printf(&quot;computer architecture is really boring\n&quot;);
		printf(&quot;I want to throw an exception\n&quot;);
		longjmp(jumpBuf, E_comp326);
	}
	printf(&quot;I continue studying comp326\n&quot;);
}

//there is 10% chance, I would complain----throw an expception for protest
void comp444()
{
	if (rand()%100&lt;10)
	{
		printf(&quot;system software design is exciting\n&quot;);
		printf(&quot;if I throw exception, I know I would quit all\n&quot;);
		longjmp(jumpBuf, E_comp444);
	}
	printf(&quot;I continue studying comp444 should I complain about anything?\n&quot;);
}	</pre>

<p>&nbsp;</p>

<p>****************<br>
now it is week 1<br>
****************************<br>
I continue studying chem205<br>
computer architecture is really boring<br>
I want to throw an exception<br>
I know you are suffering from comp326,you still have to hold on<br>
*************************<br>
I continue studying comp444 should I complain about anything?<br>
statistic has too many integral caculus<br>
I want to throw an exception<br>
I know you are suffering from stat250,you still have to hold on<br>
*************************<br>
****************<br>
now it is week 2<br>
****************************<br>
I continue studying chem205<br>
computer architecture is really boring<br>
I want to throw an exception<br>
I know you are suffering from comp326,you still have to hold on<br>
*************************<br>
I continue studying comp444 should I complain about anything?<br>
I continue studying stat250<br>
****************<br>
now it is week 3<br>
****************************<br>
chemstry has too many compound name to memorize<br>
I want to throw an exception<br>
I know you are suffering from chem205,you still have to hold on<br>
*************************<br>
computer architecture is really boring<br>
I want to throw an exception<br>
I know you are suffering from comp326,you still have to hold on<br>
*************************<br>
I continue studying comp444 should I complain about anything?<br>
statistic has too many integral caculus<br>
I want to throw an exception<br>
I know you are suffering from stat250,you still have to hold on<br>
*************************<br>
****************<br>
now it is week 4<br>
****************************<br>
I continue studying chem205<br>
computer architecture is really boring<br>
I want to throw an exception<br>
I know you are suffering from comp326,you still have to hold on<br>
*************************<br>
I continue studying comp444 should I complain about anything?<br>
statistic has too many integral caculus<br>
I want to throw an exception<br>
I know you are suffering from stat250,you still have to hold on<br>
*************************<br>
****************<br>
now it is week 5<br>
****************************<br>
chemstry has too many compound name to memorize<br>
I want to throw an exception<br>
I know you are suffering from chem205,you still have to hold on<br>
*************************<br>
computer architecture is really boring<br>
I want to throw an exception<br>
I know you are suffering from comp326,you still have to hold on<br>
*************************<br>
I continue studying comp444 should I complain about anything?<br>
statistic has too many integral caculus<br>
I want to throw an exception<br>
I know you are suffering from stat250,you still have to hold on<br>
*************************<br>
****************<br>
now it is week 6<br>
****************************<br>
chemstry has too many compound name to memorize<br>
I want to throw an exception<br>
I know you are suffering from chem205,you still have to hold on<br>
*************************<br>
computer architecture is really boring<br>
I want to throw an exception<br>
I know you are suffering from comp326,you still have to hold on<br>
*************************<br>
I continue studying comp444 should I complain about anything?<br>
statistic has too many integral caculus<br>
I want to throw an exception<br>
I know you are suffering from stat250,you still have to hold on<br>
*************************<br>
****************<br>
now it is week 7<br>
****************************<br>
I continue studying chem205<br>
computer architecture is really boring<br>
I want to throw an exception<br>
I know you are suffering from comp326,you still have to hold on<br>
*************************<br>
I continue studying comp444 should I complain about anything?<br>
statistic has too many integral caculus<br>
I want to throw an exception<br>
I know you are suffering from stat250,you still have to hold on<br>
*************************<br>
****************<br>
now it is week 8<br>
****************************<br>
chemstry has too many compound name to memorize<br>
I want to throw an exception<br>
I know you are suffering from chem205,you still have to hold on<br>
*************************<br>
computer architecture is really boring<br>
I want to throw an exception<br>
I know you are suffering from comp326,you still have to hold on<br>
*************************<br>
I continue studying comp444 should I complain about anything?<br>
statistic has too many integral caculus<br>
I want to throw an exception<br>
I know you are suffering from stat250,you still have to hold on<br>
*************************<br>
****************<br>
now it is week 9<br>
****************************<br>
chemstry has too many compound name to memorize<br>
I want to throw an exception<br>
I know you are suffering from chem205,you still have to hold on<br>
*************************<br>
computer architecture is really boring<br>
I want to throw an exception<br>
I know you are suffering from comp326,you still have to hold on<br>
*************************<br>
I continue studying comp444 should I complain about anything?<br>
I continue studying stat250<br>
****************<br>
now it is week 10<br>
****************************<br>
I continue studying chem205<br>
computer architecture is really boring<br>
I want to throw an exception<br>
I know you are suffering from comp326,you still have to hold on<br>
*************************<br>
I continue studying comp444 should I complain about anything?<br>
statistic has too many integral caculus<br>
I want to throw an exception<br>
I know you are suffering from stat250,you still have to hold on<br>
*************************<br>
****************<br>
now it is week 11<br>
****************************<br>
chemstry has too many compound name to memorize<br>
I want to throw an exception<br>
I know you are suffering from chem205,you still have to hold on<br>
*************************<br>
computer architecture is really boring<br>
I want to throw an exception<br>
I know you are suffering from comp326,you still have to hold on<br>
*************************<br>
I continue studying comp444 should I complain about anything?<br>
statistic has too many integral caculus<br>
I want to throw an exception<br>
I know you are suffering from stat250,you still have to hold on<br>
*************************<br>
****************<br>
now it is week 12<br>
****************************<br>
I continue studying chem205<br>
computer architecture is really boring<br>
I want to throw an exception<br>
I know you are suffering from comp326,you still have to hold on<br>
*************************<br>
I continue studying comp444 should I complain about anything?<br>
statistic has too many integral caculus<br>
I want to throw an exception<br>
I know you are suffering from stat250,you still have to hold on<br>
*************************<br>
****************<br>
now it is week 13<br>
****************************<br>
chemstry has too many compound name to memorize<br>
I want to throw an exception<br>
I know you are suffering from chem205,you still have to hold on<br>
*************************<br>
computer architecture is really boring<br>
I want to throw an exception<br>
I know you are suffering from comp326,you still have to hold on<br>
*************************<br>
I continue studying comp444 should I complain about anything?<br>
statistic has too many integral caculus<br>
I want to throw an exception<br>
I know you are suffering from stat250,you still have to hold on<br>
*************************<br>
<a name="why"></a></p>

<p>&nbsp;</p>

<p><b><font color="#FF0000"><a name="fork"></a>How to convince myself that 
forked process share the file status table with parent process?</font></b></p>

<p>1. &quot;exec.o&quot; open a file and fork a child process. The child process then 
&quot;exec&quot; a new program &quot;hello.o&quot; which accept the file descriptor passed by </p>

<p>forked process as command line parameter. The new program then write more 
into the file referenced by the passed file descriptor.</p>

<p>2. In order to prove parent process and child process have the shared file 
status table, I asked parent process to write more lines after it forked a</p>

<p>child process. By doing this, the file offset should be different from the 
moment when it forked the child. But the child process write into file and the </p>

<p>content are seamless aligned. i.e. the file offset of both parent and child 
are exactly same.</p>

<p>&nbsp;</p>

<pre>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;sys/types.h&gt;

int main(int argc, char* argv[])
{
	pid_t pid;
	int fd;
	int n=10;
	char buf[20];
	char nameBuf[30];
	char fileName[]=&quot;this is string buf&quot;;
	while (n&gt;0)
	{
		sprintf(nameBuf, &quot;tempParent%d&quot;, n);
		if (open(nameBuf, O_CREAT, S_IRUSR|S_IWUSR)&lt;0)
		{
			printf(&quot;open error for parent\n&quot;);
		}
		n--;
	}

	if ((fd=open(argv[1], O_CREAT|O_WRONLY|O_SYNC|O_TRUNC,
		S_IRUSR|S_IWUSR|S_IRGRP))&lt;0)
	{
		printf(&quot;open error,\n&quot;);
		exit(7);
	}
	//
	//printf(&quot;sizeof(%s)=%d\n&quot;, fileName, sizeof(fileName));
	if (write(fd, fileName, strlen(fileName))!=strlen(fileName))
	{
		printf(&quot;probably write error\n&quot;);
	}
	printf(&quot;fd is still %d\n&quot;, fd);
	if ((pid=fork())&lt;0)
	{
		printf(&quot;fork error\n&quot;);
		exit(1);
	}
	if (pid==0)
	{
		sleep(5);
		//while (n&gt;0)
		{
			printf(&quot;I am child and printing\n&quot;);
		}
		sprintf(buf, &quot;%d&quot;, fd);
		//printf(&quot;argv[2]=%s\n&quot;, argv[2]);
		printf(&quot;argv[2]=%s and buf=%s\n&quot;, argv[2], buf);
		//only 
		//strcpy(nameBuf, &quot;./&quot;);
		//strcat(nameBuf, argv[2]);
		n=4;
		while (n&gt;0)
		{
			sprintf(nameBuf, &quot;%s%d&quot;, &quot;temp&quot;, n);
			if (open(nameBuf, O_CREAT, S_IRUSR|S_IWUSR)&lt;0)
			{
				printf(&quot;open error\n&quot;);
			}
			n--;
		}
		if (execlp(argv[2], argv[2], buf, NULL)&lt;0)
		{
			printf(&quot;exec error\n&quot;);
			exit(3);
		}
		printf(&quot;will you see this?\n&quot;);
	}
	else
	{
		printf(&quot;fd is still %d\n&quot;, fd);
		//printf(&quot;I am parent and I will write more while child is sleeping...\n&quot;);
		strcpy(buf, &quot;some more from parent&quot;);
		printf(&quot;fd=%d, strlen(buf)=%d\n&quot;, fd, strlen(buf));
		if (write(fd, buf, strlen(buf))!=strlen(buf))
		{
			printf(&quot;write error from parent\n&quot;);
		}
		lseek(fd, 0, SEEK_SET);
		close(fd);	
		exit(0);
	}
	return 0;
}</pre>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<pre>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;fcntl.h&gt;

int main(int argc, char* argv[])
{
	int fd;
	char* string=&quot;this is child&quot;;
	printf(&quot;%s and argv[1]=%s\n&quot;, string, argv[1]);
	sscanf(argv[1], &quot;%d&quot;, &amp;fd);
	printf(&quot;fd=%d and string=%s&quot;, fd, string);
	printf(&quot;file offset is %d\n&quot;, lseek(fd, 0, SEEK_CUR));
	if (write(fd, string, strlen(string))!=strlen(string))
	{
		printf(&quot;error or write\n&quot;);
		exit(7);
	}
	return 0;
}</pre>

<p>&nbsp;</p>

<p>[root@sec05 mywork]# ./exec.o ./result.txt ./hello.o<br>
fd is still 13<br>
fd is still 13<br>
fd=13, strlen(buf)=21<br>
[root@sec05 mywork]# I am child and printing<br>
argv[2]=./hello.o and buf=13<br>
this is child and argv[1]=13<br>
fd=13 and string=this is childfile offset is 0<br>
<br>
This is what is inside file &quot;result.txt&quot;. Pls note that by calling &quot;lseek&quot; in 
parent process, it causes child process overwrite contents written by parent.</p>

<p>this is childg bufsome more from parent</p>

<p>&nbsp;&nbsp;&nbsp; <b><font color="#FF0000" size="4"><a name="signal"></a>To 
convince myself the signal works and also practice function pointers and pointer 
to function pointers</font></b></p>

<pre>#include &lt;signal.h&gt;
#include &lt;stdlib.h&gt;

#define SigErr  (void(*)(int))-1
#define SigDef  (void(*)(int)) 0
#define SigUsr   (void(*)(int))1

void myHandler(int sigNo);
typedef void (*FuncPtr)(int);


FuncPtr regists(FuncPtr sigHandler, int sigNo);

typedef void (**FuncPtrPtr)(int); 

int main()
{
	//FuncPtrPtr ptr;
	FuncPtr* ptr;
	FuncPtr result;
	int n=0;
	
	result=regists(myHandler, SIGUSR1);
	ptr=&amp;result;

	printf(&quot;result is 1:%d\n&quot;, result);
	//result(SIGUSR1);
	result=regists(myHandler, SIGUSR1);
	printf(&quot;register again and result should be my handler :%d\n&quot;, result);
	(*ptr)(SIGUSR1);
	//result(SIGUSR2);
	result=regists(myHandler, SIGUSR2);
	


	printf(&quot;pid=%d\n&quot;, getpid());
	for ( ; ; )
	{
		printf(&quot;no. %d\n&quot;, n);
		n++;
		pause();
	}
	return 0;
}

FuncPtr regists(FuncPtr sigHandler, int sigNo)
{
	FuncPtr result;
        if ((result=signal(sigNo, sigHandler))==SigDef)
        {
                printf(&quot;default handling\n&quot;);
        }
        else
        {       
                if (result==SigErr)
                {
                        printf(&quot;error of register\n&quot;);
                }
                else
                {
                        if (result==SigUsr)
                        {
                                printf(&quot;signal user\n&quot;);
                        }
                        else
                        {
				//should never be here
                                printf(&quot;lets see what handler is:%d\n&quot;, result);
                                result(sigNo);
                        }
                }  
        }
	return result;
}


void myHandler(int sigNo)
{
	printf(&quot;the signal is %d\n&quot;, sigNo);
}
</pre>

<p><font color="#FF0000">The running result is like following:</font></p>

<p>[qingz_hu@alamanni ~/mywork] % gcc signal.c -o signal.exe<br>
[qingz_hu@alamanni ~/mywork] % ./signal.exe<br>
default handling<br>
result is 1:0<br>
lets see what handler is:134513992<br>
the signal is 10<br>
register again and result should be my handler :134513992<br>
the signal is 10<br>
default handling<br>
pid=31720<br>
no. 0<br>
<br>
[qingz_hu@alamanni ~/mywork] % <br>
[qingz_hu@alamanni ~/mywork] % <br>
[qingz_hu@alamanni ~/mywork] % <br>
[qingz_hu@alamanni ~/mywork] % <br>
[qingz_hu@alamanni ~/mywork] % <br>
[qingz_hu@alamanni ~/mywork] % clear<br>
[qingz_hu@alamanni ~/mywork] % ./signal.exe &amp;<br>
[1] 31775<br>
[qingz_hu@alamanni ~/mywork] % default handling<br>
result is 1:0<br>
lets see what handler is:134513992<br>
the signal is 10<br>
register again and result should be my handler :134513992<br>
the signal is 10<br>
default handling<br>
pid=31775<br>
no. 0<br>
<br>
[qingz_hu@alamanni ~/mywork] % kill -USR1 31775<br>
the signal is 10<br>
no. 1<br>
[qingz_hu@alamanni ~/mywork] % kill -USR2 31775<br>
the signal is 12<br>
no. 2<br>
[qingz_hu@alamanni ~/mywork] % kill -USR1 31775<br>
the signal is 10<br>
no. 3<br>
[qingz_hu@alamanni ~/mywork] % kill -USR2 31775<br>
the signal is 12<br>
no. 4<br>
[qingz_hu@alamanni ~/mywork] % kill -20 31775<br>
<br>
[1] + Suspended ./signal.exe<br>
[qingz_hu@alamanni ~/mywork] % <br>
&nbsp;</p>

<p><font color="#FF0000"><a name="funcPtr"></a>The function pointer array is 
manipulated like this: Actually it puzzles me several hours by figuring out how 
to declare a function pointer of which the</font></p>

<p><font color="#FF0000">return type is a function and the parameter includes a 
function pointer. </font> </p>

<p><font color="#FF0000">i.e. HandleType regists(int num, HandleType funcPtr);&nbsp; 
is a declaration of this kind of function, but how to declare a type for this 
function.</font></p>

<p><font color="#FF0000">I must admit it is extremely confusing for me to do 
this without &quot;typedef&quot; a HandleType first. (Actually I don't know how after many 
times trials.)</font></p>

<p><font color="#FF0000">&nbsp;</font></p>

<pre>#include &lt;stdlib.h&gt;


typedef void (*HandleType)(int);

typedef HandleType  (*FuncPtr1)(int, HandleType);


HandleType regists(int num, HandleType funcPtr); 

void display();

void handler1(int num);
void handler2(int num);
void handler3(int num);
void handler4(int num);
void handler5(int num);

HandleType funcArray[5]=
{
	handler1, handler2, handler3, handler4, handler5
};

int main()
{
	FuncPtr1 ptr1;
	int i;
	//FuncPtr2 ptr2;
	HandleType result;
	printf(&quot;initial condition of funcArray\n&quot;);
	display();
	ptr1=regists;
	result=handler5;
	printf(&quot;let's register handler5 at the beginning and shift all\n&quot;);
	for (i=0; i&lt;5; i++)
	{
		result=ptr1(i, result);
	}
	printf(&quot;after register, it should be like round robin\n&quot;);
	display();
	return 0;
}
	

void handler1(int num)
{
	printf(&quot;This is handler 1 and handling %d\n&quot;, num);
}

void handler2(int num)
{
	printf(&quot;This is handler 2 and handling %d\n&quot;, num);
}

void handler3(int num)
{
	printf(&quot;This is handler 3 and handling %d\n&quot;, num);
}

void handler4(int num)
{
	printf(&quot;This is handler 4 and handling %d\n&quot;, num);
}

void handler5(int num)
{
	printf(&quot;This is handler 5 and handling %d\n&quot;, num);
}

void display()
{
	int i;
	for (i=0; i&lt;5; i++)
	{
		funcArray[i](i);
	}
}

HandleType regists(int num, HandleType funcPtr)
{
	HandleType result;
	printf(&quot;this is a function takes parameter of integer and a function pointer\n&quot;);
	printf(&quot;it also returns a function pointer\n&quot;);
	result=funcArray[num];
	funcArray[num]=funcPtr;
	return result;	
}</pre>
<pre>&nbsp;</pre>
<pre><font color="#FF0000">This is the running result:</font></pre>

<p>[qingz_hu@alamanni ~/mywork] % ./funcptr.exe<br>
initial condition of funcArray<br>
This is handler 1 and handler handling 0<br>
This is handler 2 and handler handling 1<br>
This is handler 3 and handler handling 2<br>
This is handler 4 and handler handling 3<br>
This is handler 5 and handler handling 4<br>
this is a function takes parameter of integer and a function pointer<br>
it also returns a function pointer<br>
this is a function takes parameter of integer and a function pointer<br>
it also returns a function pointer<br>
this is a function takes parameter of integer and a function pointer<br>
it also returns a function pointer<br>
this is a function takes parameter of integer and a function pointer<br>
it also returns a function pointer<br>
this is a function takes parameter of integer and a function pointer<br>
it also returns a function pointer<br>
after register, it should be like round robin<br>
This is handler 5 and handler handling 0<br>
This is handler 1 and handler handling 1<br>
This is handler 2 and handler handling 2<br>
This is handler 3 and handler handling 3<br>
This is handler 4 and handler handling 4<br>
<a name="useful"></a></p>

<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">How big difference is there between</td>
    <td class="head" align="right">2005-02-07</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">different UNIX system?<br>
    <br>
    Referfing to theory assignment question 5, I know as long as the API's 
    interface are same, at least they are compatible at level of source code. 
    That's is by re-compiling the source code we can run the program in 
    variation of UNIX. My question is that is it true the variation of UNIX is 
    so different that we have to re-compile source code. i.e. some program in 
    windows are also compatible with UNIX at level of source code.<br>
    <br>
    What is the major difference between different variation of UNIX, from the 
    perspective programmer? Different data alignment, big Indian, little indian? 
    Different size of data type, like integer size? </td>
  </tr>
</table>
<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">UNIX variations</td>
    <td class="head" align="right">2005-02-09</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">I'm not sure that I completely understand your 
    question. The question on the assignment referred to the fact that if we use 
    system calls on a POSIX compliant OS, we can expect to be able to port the 
    source code to another POSIX compliant OS and recompile and run our code 
    without problems (at least with respect to the system calls). This is the 
    case because even though the calls are implemented differently, the name, 
    parameters, return value, and meaning (i.e., semantics) are the same. Since 
    Windows is &quot;somewhat&quot; POSIX compliant (exactly how much I'm not sure), we 
    may often be able to take source from a Unix system and recompile it on 
    Windows without too much of a problem.<br>
    <br>
    Re-compilation is necessary, however, even with two POSIX compliant system 
    since the hardware (and hence instruction set) may be different, as well as 
    the executable file format. The things that you mention - big endian, 
    integer size, alignment - are all related to hardware and are usually 
    irrelevant to the programmer. The endianess issue, for example, is handled 
    by the compiler on each platform. There are exceptions to this, of course. 
    The limits.h header file, for instance, lists things like maximum size of an 
    integer which may be important to a particular program. You may also have to 
    worry about endianess if you are creating files that must be read on 
    different hardware platforms. But these are the exceptions. In general, you 
    don't worry about these issues when porting code between version of UNIX.<br>
    <br>
    Dr Eavis </td>
  </tr>
</table>
<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">How to declare type of function &quot;signal&quot;</td>
    <td class="head" align="right">2005-02-12</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">I always suspect the declaration of &quot;signal&quot; 
    function is actually a function pointer. And when I tried to declare a type 
    of such function pointer, I run into difficulty. What I want to declare is a 
    function pointer type such that its return type is a function and one of its 
    two parameter is also a function pointer. i.e. This won't work:<br>
    <br>
    typedef void(*MyType(int, void(*)(int)))(int);<br>
    <br>
    The compiler gives error of something like declaring a function returning a 
    function. So, I guess compiler thinks I am declaring a variable instead of 
    type definition?? Later I finally divide the job into two step and it works. 
    But I just don't know why.<br>
    <br>
    typedef void (*HandleType)(int);<br>
    <br>
    typedef HandleType (*FuncPtr1)(int, HandleType); </td>
  </tr>
</table>
<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">OK, I think I figured out,</td>
    <td class="head" align="right">2005-02-12</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">By adding one extra pair of parenthesis, 
    compiler understands my intention that return type is a function: void (*)(int).<br>
    <br>
    And the type definition is inside another parenthesis:<br>
    <br>
    ((*MyType)(int, void(*)(int))) <br>
    <br>
    i.e. It finally is something like this:<br>
    <br>
    typedef void (*((*MyType)(int, void(*)(int)) ) )(int); </td>
  </tr>
</table>

<p>&nbsp;</p>

<p><b><font color="#FF0000">bad programming habit</font></b></p>

<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">share file after fork()</td>
    <td class="head" align="right">2005-02-12</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">I write code as follows and get unexpected 
    result. Any help?<br>
    <br>
    #include
    <sys types.h><br>
    <br>
    #include
    <sys stat.h><br>
    <br>
    #include
    <fcntl.h><br>
    <br>
    #include
    <stdio.h><br>
    <br>
    int main(int argc, char *argv[])<br>
    <br>
    {<br>
    <br>
    int fd;<br>
    <br>
    unlink(&quot;fork&quot;);<br>
    <br>
    fd = open(&quot;fork&quot;, O_CREAT|O_WRONLY|O_SYNC, S_IRWXU);<br>
    <br>
    printf(&quot;this is main\n&quot;);<br>
    <br>
    switch (fork())<br>
    <br>
    {<br>
    <br>
    case -1 :<br>
    <br>
    perror(&quot;fork()&quot;);<br>
    <br>
    exit(1);<br>
    <br>
    break;<br>
    <br>
    case 0:<br>
    <br>
    write(fd, &quot;this is fork\n&quot;, 60);<br>
    <br>
    exit(1);<br>
    <br>
    break;<br>
    <br>
    default:<br>
    <br>
    write(fd, &quot;this is parent\n&quot;, 20);<br>
    <br>
    exit(1);<br>
    <br>
    break;<br>
    <br>
    }<br>
    <br>
    return(0);<br>
    <br>
    }<br>
    <br>
    content in file fork:<br>
    <br>
    this is parent<br>
    <br>
    this is fork<br>
    <br>
    this is parent<br>
    <br>
    question:<br>
    <br>
    where the second &quot;this is parent&quot; from?<br>
    <br>
&nbsp;</stdio.h></fcntl.h></sys></sys></td>
  </tr>
</table>
<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">This is probably due to a bad habit</td>
    <td class="head" align="right">2005-02-12</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">I tried the code with little modification and 
    everything works fine. And my explanation is that your puzzle probably due 
    to a bad habit of programming.<br>
    <br>
    The only difference I made in my code is that the number of bytes I write is 
    exactly the length of the buffer. i.e.<br>
    <br>
    ...<br>
    <br>
    char* str1=&quot;this is parent&quot;;<br>
    <br>
    ...<br>
    <br>
    write(fd, str1, strlen(str1));<br>
    <br>
    ...<br>
    <br>
    Please note that in your code you unnecessarily ask write to write 60 bytes 
    and you are probably write some extra garbage into file. If my guess is 
    correct, then when you write &quot;this is fork&quot;, you are probably also write 
    string &quot;this is parent\n&quot; into file since you are write length of 60bytes. 
    Usually string like &quot;this is parent&quot; are treated as constant data by 
    compiler and probably both &quot;this is fork&quot; and &quot;this is parent&quot; strings are 
    allocated in &quot;initialized data segment&quot; together. There are very big chance 
    that they are allocated in neighbour memory address. So, by coincidence you 
    think you write one string twice. <br>
    <br>
    This is my guess, however, I am pretty sure it is the problem. You can try 
    to modify your code and test.<br>
    <br>
    n.h. </td>
  </tr>
</table>
<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">fork</td>
    <td class="head" align="right">2005-02-14</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">Yes, n.h. is correct. The two strings are 
    likely to be right next to one another in memory and because you use a large 
    count value, both strings get written at once in the child process.<br>
    <br>
    Dr Eavis </td>
  </tr>
</table>

<p><b><font color="#FF0000">memory address space</font></b></p>

<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">About function dynamic library</td>
    <td class="head" align="right">2005-02-13</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">What I understand is that if our executable 
    file dynamically links with some library, then the code text in library will 
    not be counted in memory space of our executable program. i.e. The address 
    of symbols in function of library will not be calculated as relative offset 
    of the beginning address of our program. In other words, the memory of 
    library function is outside of limit of virtual memory space, say 4G. Is 
    this correct?<br>
    <br>
    Another question puzzles me if the above is correct. When we pass parameter 
    to library function, where does system store the parameter? Obviously it is 
    not passed to our program's user space stack because I think library 
    function is not even located in our local stack frame. Then is it possible 
    that it is located in each program's kernel stack? This sounds reasonable 
    when I recall it is mentioned in lecture. But I am not so sure. <br>
    <br>
    Thank you sir.<br>
    <br>
&nbsp;</td>
  </tr>
</table>
<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head"><a name="memory"></a>process memory</td>
    <td class="head" align="right">2005-02-14</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">All library code, whether statically or 
    dynamically linked, will be part of our address space. In the dynamic case, 
    the addresses of library functions must be &quot;fixed up&quot; at run-time. But 
    ultimately, they must still be part of that 4GB address space.<br>
    <br>
    By extension, this implies that a common user mode stack is used in all 
    cases. <br>
    <br>
    The real difference is simply that the library code does not become part of 
    the &quot;stored&quot; executable, thereby allowing many user programs to share one 
    copy of the library code...with each process seeing the text segment of the 
    shared library as part of its own address space. <br>
    <br>
    Dr Eavis </td>
  </tr>
</table>
<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">dynamic linking</td>
    <td class="head" align="right">2005-02-14</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">Thank you sir for your explanation. However, I 
    think I still believe that the library code which is dynamically linked will 
    not be part of 4GB address space of our program. The reason is like this:<br>
    <br>
    1. From what we learned in comp229, we know the functions and variables in 
    library will become unresolved external symbols in executable files after 
    linking because linker has no way to calculate the actual address of library 
    code either because they can be anywhere in memory when program is loaded or 
    it is not the job of linker at this stage since the linking will be 
    accomplished only at runtime. Usually we can even use a &quot;stub&quot; file to 
    represent library code when compiling and the so-called stub file is 
    essentially the header file which gives the interface of library function 
    only. By doing this we have the flexibity to upgrade library without 
    re-compiling executable files as long as the interface of library remains 
    unchanged. So, we know for sure the implementation of library code is not 
    needed at the stage of compilation. <br>
    <br>
    2. At runtime, the linking-loader will resolve those unresolved external 
    symbols, the functions in library, by help of operating system. And those 
    symbols will only need to be changed with a pointer which points to actual 
    &quot;absolute&quot; address of functions in library when library is loaded in memory. 
    And PC(program counter)jumps to the entry of functions and when function 
    finishes PC jumps back to the next instruction before function call. There 
    is no need and no possibility for our program to &quot;reference&quot; anything other 
    than the &quot;name of function&quot;. So, the address referenced in code for the name 
    of function in library will be only using &quot;absolute&quot; address instead of 
    relative address. And I think this is like the &quot;long jump&quot; in early pascal 
    language when you call some function located in other module. But the 
    difference is that &quot;long jump&quot; will be resolved during linking stage when 
    different modules are combined together and all module are allocated with 
    memory address within 4GB. Whilst dynamic linking can never determine the 
    memory address of library until runtime and the address of library is 
    obtained by help of operating system whenever the function name is called. 
    My opinion is that the function name of library is always treated as an 
    external symbol and it is not part of 4GB memory space of our program. 
    Because &quot;absolue&quot; address is not counted in any part of virtual memory 
    address. </td>
  </tr>
</table>

<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">absolute address</td>
    <td class="head" align="right">2005-02-14</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">After I posted my opinion above, I searched 
    again for the definition of &quot;absolute&quot; address mode and I am sorry I am 
    wrong about concept of &quot;phycial memory address&quot; and &quot;absolute address&quot;. 
    &quot;Absolute address&quot; is still part of virtual memory address which is mapped 
    by VMM. However, my argument above remains unchanged when replacing absolute 
    address with physical address. Because we know the implementation of library 
    is actually independent from our executable files. That is to say, after 
    upgrading of our library, the size of code maybe vary and still our program 
    can run smoothly. This implies we don't need care about the address or size 
    of library function. Therefore it proves the library is outside 4GB memory 
    address.<br>
    <br>
&nbsp;</td>
  </tr>
</table>

<p>&nbsp;</p>

<p><a name="preemptable"></a><b><font color="#FF0000">pre-emptable and 
interruptable?</font></b></p>

<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">So, system call can be interrupted</td>
    <td class="head" align="right">2005-02-14</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">In page275, it is said that system call can be 
    interrupted if it happens to be a &quot;slow&quot; one. I then recall the first 
    assignment about preemption of kernel code since system calls are in mode of 
    kernel, right? I get a bit confused about these two concepts: &quot;interruptable 
    and preemptable.&quot; Does the fact that system call can be interrupted suggest 
    that it can be preempted? Or is term &quot;preemption&quot; only applicable for 
    inter-process instead of functions within one process space? <br>
    <br>
    I check again with solution of first assignment and guess the term &quot;reentrant&quot; 
    is very similar to &quot;interruptable&quot; because it is due to &quot;interrupt&quot;(soft or 
    hardware) which enables &quot;reentrance&quot;. Is it right? </td>
  </tr>
</table>
<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">syscall interruption</td>
    <td class="head" align="right">2005-02-14</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">Yes, these terms are a little confusing since 
    they refer to similar issues. In terms of pre-emption, this refers to the 
    notion of a process being &quot;stopped&quot; so that another process can run. This 
    can certainly happen with user-mode processes since it is one of the primary 
    scheduling mechanisms. For most kernels, however, it is not possible for 
    executing kernel code to be pre-empted so that another user mode process can 
    be run. Real-time OSs like Solaris are exceptions to this rule (from what I 
    understand, the new Linux 2.6 kernel may also provide some degree of kernel 
    pre-emption as well)<br>
    <br>
    Kernel calls are interruptable, however. So when a signal arrives during the 
    execution of a system call, the traditional response has been to terminate 
    the syscall with an appropriate error return code. But this causes no 
    problem with kernel &quot;corruption&quot; because the interrupt would only be 
    delivered while the system call was blocked...say while waiting for the 
    disk. At this point, system data structures are in a consistent state. In 
    other words, the sys call doesn't get interrupted in a random location. And 
    it makes sense to interrupt a &quot;slow&quot; system call at this point since the 
    signal is likely to be something that has to be addressed immediately. But 
    keep in mind that all of this is happening to one process. We are not 
    pre-empting one process to run another.<br>
    <br>
    Re-entrance refers to a multi-process (or mutli-function) situation. For 
    example, if one process blocks in a system call, it is possible for a second 
    process to get the CPU and then execute that same system call. If a function 
    is re-entrant, it can allow this without risk of corrupting or re-writing 
    any internal variables or data structures.<br>
    <br>
    Dr Eavis </td>
  </tr>
</table>

<p>&nbsp;</p>

<p><font color="#FF0000"><a name="second"></a><b>My second assignment:</b></font></p>

<p>Questions:</p>

<pre>1. File permission bits are generally easy to understand. However, directory
permissions are a little less intuitive. Explain how the executable bit is used
for directories and why it is different than the read bit.
2. When we open a file, we have the option of specifying the O_SYNC flag. We
can also obtain synchronization functionality by using the sync system call.
What is the difference between the two and what effect do they have on the
data located in the C library buffers. Explain.
3. The chdir system call can be used to modify the current working directory.
Say that we use chdir within a program to move to a completely new
directory. Our program then creates another process (say with fork) that
shares the same cwd. After our program terminates, however, and we get our
command prompt back, we’re still in the same directory that we were in
before we ran our program. Why does this happen?
4. With respect to the standard C libraries, explain how it is possible to do a lineoriented
write (e.g., fputs) that does not cause a line of data to be sent to the
kernel.
5. We saw with fopen that this C library call invokes the system call open (and
adds some extra functionality). Now, the OS provides a positioning function
called lseek. The C libraries provide a positioning function called fseek. So is
fseek a wrapper for lseek or is it possible to invoke fseek without lseek ever
being called?</pre>
<pre>6. There are two types of libraries: static and shared. The book suggests that
shared libraries make our executables smaller. Let’s say that the standard C
libraries could be compiled as either static or shared libraries. With respect to
the diagram on page 168 (the process space), explain the effect of using the
static version versus the shared version.
7. We said that the file system tries to ensure that directory inodes are spread
more or less evenly across block groups. This sounds nice but, really, why is
it useful?
8. Let’s say that we are using an ext2 file system that uses a block size of 1024
bytes. We create a file that contains 856,000 bytes. How will the file’s inode
keep track of these blocks? Be specific here and show the math.
9. I have just purchased a new hard disk that holds 80 GB of data and I have set
up a partition that is 30 GB in size. I install the ext2fs in this partition,
specifying a block size of 2048 bytes. What is the maximum number of data
blocks that I can store in a block group with this configuration?</pre>

<p>&nbsp;</p>

<ol style="margin-top: 0cm; margin-bottom: 0cm" start="1" type="1">
  <li class="MsoNormal" style="line-height: 200%">
  <span style="font-size:12.0pt;line-height:200%">If only the “read” bit is set 
  for a directory, then it can only be listed with the file names contained in 
  the directory. (i.e. “ls directory-name”. And even the switch “-l” cannot be 
  added since only the name of “dirent” can be retrieved. In order to retrieve 
  more information like access time, size etc, the directory needs to be 
  “executed” by some system call like “stat” etc.) Without setting the 
  “execution bit”, all the files inside the directory cannot be executed and 
  even the directory itself cannot be executed. Then we cannot open any file and 
  even cannot list detailed information of contained files in directory. </span>
  </li>
  <li class="MsoNormal" style="line-height: 200%">
  <span style="font-size:12.0pt;line-height:200%">By specifying “O_SYNC” flag, 
  every write call will only return until all data are written to O.S. I/O 
  buffer and this is an atomic operation compared with invoking “sync” system 
  call. i.e. Between “write” call and “sync”, there maybe context switch 
  happened between processes and with flag “O_SYNC” this won’t happen. System 
  calls like “write”, “read” are un-buffered call and they don’t use C library 
  buffer. Instead they write directly into system I/O buffer. There is no direct 
  relation between system call and C library buffer except that usually C 
  library file API uses system calls for implementation. So, when C library 
  function like “fread”, “fwrite” is called, internally system call like “read” 
  and “write” is often called and C library buffer may be read and written.
  </span></li>
  <li class="MsoNormal" style="line-height: 200%">
  <span style="font-size:12.0pt;line-height:200%">Our current working directory 
  is one of environment parameter recorded in system data file, i.e. “passwd” 
  file. And the shell always direct user to its “CWD” in user prompt. So, even 
  in the program, “chdir” is called, after the program finishes, the shell will 
  still retrieve user’s current working directory information from environment 
  parameter file and direct user prompt into its CWD indicated by environment 
  parameter.&nbsp;&nbsp;&nbsp; </span></li>
  <li class="MsoNormal" style="line-height: 200%">
  <span style="font-size:12.0pt;line-height:200%">In C library there is an 
  internal buffer to hold data ready to be written into operating system I/O 
  buffer. Usually this buffer has a fairly large size compared with length of a 
  common line, say with size of 256. Therefore when “fputs” is called, say a 
  line of string shorter than size of buffer is written into this internal 
  buffer. As long as the buffer is not full, C library will not flush contents 
  in buffer to system I/O buffer.</span></li>
  <li class="MsoNormal" style="line-height: 200%">
  <span style="font-size:12.0pt;line-height:200%">In C library, a structure 
  called FILE is used to maintain file-related information. One of its fields is 
  used to record current offset of file operation. Therefore when “fseek” is 
  called, C library just calculates the offset field of FILE structure without 
  invoking “lseek” call. i.e. when user want to forward n bytes from current 
  position, library just call “read” (n/buffer_size +1) times to read contents 
  into internal buffer. More possibly when the number of bytes user wants to 
  move is smaller than size of internal buffer, C library just modify the 
  current pointer pointing to the position of internal buffer without making any 
  system call. </span></li>
  <li class="MsoNormal" style="line-height: 200%">
  <span style="font-size:12.0pt;line-height:200%">When we use static linking to 
  compile our executable file, compiler will compile all functions and variables 
  in library into our executable file. That is to say, when the program is 
  loaded into memory the code in library will also be part of “text”, 
  “initialized” ,“uninitialized” segment since these functions and variables are 
  treated no difference from other codes. Of course when program is running, 
  those library functions are also part of stack frame of process in the “stack” 
  segment. The function and variables in library are also part of memory space 
  in our program. Therefore the size of run-time process is much large. In 
  contrast, when we use dynamic linking, the functions in library will be 
  represented only as external symbol which will only be linked and resolved at 
  run-time by dynamic loading and linking done by operating system. Since 
  functions and variables in library will ONLY be symbols in “text” segment in 
  executable files when stored in disk and memory pointers resolved by 
  loader_and_linker when program is loaded into memory, the size of executable 
  is much smaller compared with static linking. At run-time, functions and 
  variables in library are not even located in memory space of process. i.e. 
  Their address is not treated as relative offset from beginning address of our 
  program module. So the size of run-time is also reduced.</span></li>
  <li class="MsoNormal" style="line-height: 200%">
  <span style="font-size:12.0pt;line-height:200%">This is to make file access 
  performance better. When users access directory, their real purpose is to try 
  to access files contained in directory or retrieve information of those files, 
  i.e., read, write contents in file or browse information like size, access 
  time of files. By “principle of locality”, if directory and files in it are 
  located in same block group, the O.S. can achieve a better performance in a 
  sense that I/O operation is quite a time-consuming operation. In order to 
  allow directory and its containing files in same block groups, it is necessary 
  for file system NOT to store directories’ inodes into one particular block 
  group. Otherwise when number of files contained in each directory increases, 
  one block group will be unable to hold those data blocks and inodes of new 
  files. Therefore to cope with increase of number of files in each directory, 
  file system usually needs to allocate directory inodes averagely across whole 
  block groups.</span></li>
  <li class="MsoNormal" style="line-height: 200%">
  <span style="font-size:12.0pt;line-height:200%">In the inode of a file, there 
  is one field called data block pointer which consists of 15 data block 
  pointers. The first 12 of them are direct pointers of which each points to one 
  data block. The rest 3 of them are indirect, double indirect and triple 
  indirect pointers. </span></li>
</ol>
<p class="MsoNormal" style="margin-left:36.0pt;line-height:200%">
<span style="font-size:12.0pt;line-height:200%">Number of pointers in one block: 
1024 / 4 = 256(pointers/block)</span></p>
<p class="MsoNormal" style="margin-left:36.0pt;line-height:200%">
<span style="font-size:12.0pt;line-height:200%">a)&nbsp; 856000/1024=835.9(blocks)&nbsp;&nbsp; 
//it exceeds 12 direct pointers</span></p>
<p class="MsoNormal" style="margin-left:36.0pt;line-height:200%">
<span style="font-size:12.0pt;line-height:200%">b)&nbsp; (836-12)/256 = 3.22 &gt;1&nbsp;&nbsp;&nbsp;&nbsp; 
//it exceeds indirect pointer</span></p>
<p class="MsoNormal" style="margin-left:36.0pt;line-height:200%">
<span style="font-size:12.0pt;line-height:200%">c)&nbsp; (836-12-256) /256 = 2.2 
&lt;256&nbsp;&nbsp;&nbsp; //it falls within double indirect pointer</span></p>
<p class="MsoNormal" style="margin-left:36.0pt;line-height:200%">
<span style="font-size:12.0pt;line-height:200%">As shown above, 12 direct 
pointer and indirect and double indirect pointer are used to bookkeeping total 
836 data blocks. Assuming the index of data block starts from 0, when the index 
of data block is smaller than 12, the index of block is the index of direct data 
pointer. When the index of block is within range between 12 and 12+256-1=267, 
the address is in the pointer block pointed by indirect data block pointer. When 
index of block is in range between 268 and 836, the address of data block can be 
retrieved by following double indirect data block pointer.</span></p>
<p class="MsoNormal" style="line-height:200%">
<span style="font-size:12.0pt;
line-height:200%">&nbsp; 9. &nbsp;30G/2K/(2K x 8) = 960(blocks)</span></p>

<p class="MsoNormal" style="line-height:200%">
&nbsp;&nbsp;&nbsp; <b><font color="#FF0000" size="4"><a name="signalCount"></a>
Signal!Signal!!Signal!!!</font></b></p>

<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">Is signal queued in process table's list</td>
    <td class="head" align="right">2005-02-23</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">I am not sure if I have asked the same 
    question. However, my test and answer from different source still conflicts.<br>
    <br>
    1. Assume a parent process forks several child processes and goes to sleep.<br>
    <br>
    2. During period when parent is asleep, each child process sends parent a 
    signal, say SIGUSR!, an arbitrary times. When parent process wakes up, how 
    many times does the handler of signal SIGUSR1 have been executed? <br>
    <br>
    a) Is it the sum of times each child sends? Obviously not and my test 
    confirms this.<br>
    <br>
    b) Is it number of child processes? I am not sure because it doesn't make 
    much senses. Since I only test two or three children cases, I am not sure it 
    is by coincidance or not.<br>
    <br>
    c) Is it only ONCE? If the signal list is implemented by a bitmap, this 
    should make senses. Because no matter how many signals of same type are 
    received, it only show one occurrance.<br>
    <br>
    d) Is it an undefined number? My test seems to favour this assumption. But I 
    still don't understand the reason. <br>
    <br>
    The following is my test program and the running results. <br>
&nbsp;</td>
  </tr>
</table>
<pre>#include &lt;stdio.h&gt;
#include &lt;signal.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;time.h&gt;
int count=0;
int signalCount=0;
void handler(int no);

void childCount(int no);

const int ChildNumber=10;
int main()
{
	int i;
	pid_t pid;
	srand(time(0));
	if (signal(SIGUSR1, handler)==SIG_ERR)
	{
		printf(&quot;error of signal\n&quot;);
	}
	if (signal(SIGCHLD, childCount)==SIG_ERR)
	{
		printf(&quot;error of signal\n&quot;);
	}		
	for (i=ChildNumber; i&gt;0; i--)
	{
		if ((pid=fork())==0)
		{
			sleep(i);
			i=rand()%i;
			printf(&quot;child %d sends signal %d times\n&quot;, getpid(), i);
			while(i&gt;0)
			{
				kill(getppid(), SIGUSR1);
				i--;
			}
			exit(0);
		}
	}
	sleep(ChildNumber);
	while (count&lt;ChildNumber)
	{
		pause();
	}
	return 0;

}

void childCount(int no)
{
	count++;
	printf(&quot;%d child dies\n&quot;, count);
}


void handler(int no)
{
	signalCount++;
	printf(&quot;user1 signal number %d\n&quot;, signalCount);
}</pre>

<p><font color="#FF0000">This is the running result when redirected to a file:</font></p>

<p>child 32303 sends signal 0 times<br>
child 32302 sends signal 1 times<br>
child 32301 sends signal 0 times<br>
child 32300 sends signal 3 times<br>
child 32299 sends signal 1 times<br>
child 32298 sends signal 3 times<br>
child 32297 sends signal 2 times<br>
child 32296 sends signal 7 times<br>
child 32295 sends signal 0 times<br>
child 32294 sends signal 1 times<br>
1 child dies<br>
user1 signal number 1<br>
2 child dies<br>
3 child dies<br>
user1 signal number 2<br>
4 child dies<br>
user1 signal number 3<br>
5 child dies<br>
user1 signal number 4<br>
6 child dies<br>
user1 signal number 5<br>
7 child dies<br>
user1 signal number 6<br>
user1 signal number 7<br>
user1 signal number 8<br>
8 child dies<br>
9 child dies<br>
user1 signal number 9<br>
10 child dies<br>
&nbsp;</p>

<p><font color="#FF0000">This is the running result when executed from command 
line. The display has some subtle difference, but the big picture is similar:</font></p>

<p><font face="Times New Roman">child 32463 sends signal 0 times<br>
<br>
1 child dies<br>
<br>
child 32462 sends signal 1 times<br>
<br>
user1 signal number 1<br>
<br>
2 child dies<br>
<br>
user1 signal number 1<br>
<br>
child 32461 sends signal 0 times<br>
<br>
3 child dies<br>
<br>
child 32460 sends signal 1 times<br>
<br>
user1 signal number 2<br>
<br>
4 child dies<br>
<br>
user1 signal number 2<br>
<br>
child 32459 sends signal 4 times<br>
<br>
user1 signal number 3<br>
<br>
5 child dies<br>
<br>
user1 signal number 3<br>
<br>
child 32458 sends signal 3 times<br>
<br>
user1 signal number 4<br>
<br>
6 child dies<br>
<br>
user1 signal number 4<br>
<br>
child 32457 sends signal 4 times<br>
<br>
user1 signal number 5<br>
<br>
7 child dies<br>
<br>
user1 signal number 5<br>
<br>
child 32456 sends signal 5 times<br>
<br>
user1 signal number 6<br>
<br>
8 child dies<br>
<br>
user1 signal number 6<br>
<br>
child 32455 sends signal 6 times<br>
<br>
user1 signal number 7<br>
<br>
9 child dies<br>
<br>
user1 signal number 7<br>
<br>
child 32454 sends signal 9 times<br>
<br>
user1 signal number 8<br>
<br>
10 child dies<br>
<br>
user1 signal number 8<br>
</font><br>
<b><font color="#FF0000"><a name="suspend"></a>The behaviour of&nbsp; 
sigsuspend(sigset_t*) (A personal reminder)</font></b></p>

<p>1. When you fork a new child, the child inherits the signal mask except 
signal handler. This makes senses since signal handler is just a function 
existing in parent address space.</p>

<p>2. No matter whatever signal you block, signal mask will be reset by 
parameter of sigsuspend(sigset_t*). This is stated very clearly, but I simply 
didn't get it or believe it until I tried by myself.</p>

<p>3. When sigsuspend() is interrupted, it catches some signal which is not in 
the block list and reset block-mask to original one.</p>

<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">Problem with sigaction</td>
    <td class="head" align="right">2005-03-02</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">The tutor for the lab say that it's better to 
    use sigaction instead of signal, as say on the book page 296. So I've put 
    the fonction of the page 298 on my program, but when I compile it, it said:<br>
    <br>
    size of storage for ?act ?is not known, and the same thing for oact. I don't 
    know where is the problem since it's the code given in the book, and I 
    thought it should working.
    <table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
      <tr>
        <td class="head">Have you typed &quot;struct&quot; before sigaction</td>
        <td class="head" align="right">2005-03-03</td>
      </tr>
      <tr>
        <td class="body" colSpan="2">In C, the function and structure can use 
        same name and it fools me a couple of times. If you only type &quot;sigaction&quot; 
        without adding &quot;struct&quot; before it, the &quot;sizeof&quot; function will give this 
        error if you are using it. This happened to me once. </td>
      </tr>
    </table>
    </td>
  </tr>
</table>

<p>&nbsp;</p>

<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">Some discoveries of &quot;pipe&quot;<a name="pipe"></a></td>
    <td class="head" align="right">2005-03-03</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">1. You don't have to close one &quot;read&quot; at writer 
    side and close the &quot;write&quot; descriptor at reader side EXPICITLY. They will 
    work fine and I think it is only a good programming habit to prevent other 
    process both reads and writes from the other end of pipe. Because by closing 
    read, pipe cannot be written from other side. (Maybe this is the reason of 
    &quot;half-duplex&quot; since multiple read will destroy the internal pointer.)<br>
    <br>
    2. I deliberately tried to read from both side and write from only one side. 
    Even though both read get the message, however, the later read is not a 
    BLOCKED read anymore. i.e. Every call of read from the second read is always 
    returned immediately.<br>
    <br>
    3. In Linux, &quot;PIPE_BUF&quot; constant is undefined. And what's worse, it seems 
    you can write however big size of data you like. In my case, I tried size of 
    1024x1024 bytes of buffer for writing. The write and read both works fine. 
    The following is the test program. <br>
    <br>
    4. I dimly remembered in O.S. course, the professor mentioned about &quot;pipe&quot; 
    and the &quot;read&quot; and write operation is synchronized internally. But I am not 
    sure.<br>
    <br>
    5. The logic of my program is like this:<br>
    <br>
    i) create a large buffer and I initialize it by writing &quot;block&quot; number into 
    their position. i.e. no. m is at the position of m*BlockSize. By doing this, 
    I can check the output file if data is corrupted by overlapping.<br>
    <br>
    ii) Parent write the whole buffer into pipe and child read from buffer and 
    write into an output file.<br>
    <br>
    iii)The buffer size should already exceed internal pipe buffer size. However 
    the write call doesn't split its operation to several writes. I know this by 
    counting the reading operation. It is a single write and a single read. I 
    guess O.S. synchronizes the read and write internally, otherwise there is 
    nothing special for &quot;pipe&quot; which is a file.<br>
    <br>
&nbsp;</td>
  </tr>
</table>
<pre>#include &lt;sys/stat.h&gt;
#include &lt;unistd.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;stdio.h&gt;

const int LineSize=1024*1024;
#define  BlockSize 16
char* outname=&quot;out.txt&quot;;
const int Permission=S_IRUSR|S_IWUSR|S_IRGRP;
char block[BlockSize]={0};
int fds[2];

int main(int argc, char* argv[])
{
	pid_t pid;
	char buf[LineSize];
	int fdin, fdout, i=0, n=0;
	char msg[20];
	if (pipe(fds)&lt;0)
	{
		printf(&quot;pipe error\n&quot;);
	}
	
        if ((fdout=open(outname, O_WRONLY|O_CREAT, Permission))==-1)
        {
                printf(&quot;write open error\n&quot;);
        }
	//initialize buf to be full of number of blocks...
	while (n&lt;LineSize/BlockSize)
	{
		sprintf(block, &quot;no.%d\n&quot;, n+1);
		i=strlen(block);
		//just pad space after number
		while (i!=BlockSize-1)
		{
			block[i]=' ';
			i++;
		}
		block[BlockSize-1]='\n';
		
		strcpy(buf+n*BlockSize, block);
		n++;
	}
		
		
	if ((pid=fork())==0)
	{
		while ((n=read(fds[0], buf, LineSize))&gt;0)
		{
			if (write(fdout, buf, n)!=n)
			{
				printf(&quot;write to output error\n&quot;);
			}
			sprintf(msg, &quot;child read %d\n&quot;, n);
			if (write(STDOUT_FILENO, msg, strlen(msg))!=strlen(msg))
			{
				printf(&quot;display error\n&quot;);
			}		
		}
	}
	else
	{
		if (write(fds[1], buf, LineSize)!=LineSize)
		{
			printf(&quot;write error\n&quot;);			
		}
	}
	return 0;
}
	<a name="sigpipe"></a></pre>

<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">The signal SIGPIPE is necessary</td>
    <td class="head" align="right">2005-03-04</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">Regarding my question in class about SIGPIPE, 
    it seems the signal is necessary because there is nothing wrong for the 
    writer to write even though the reader has already closed the read end. The 
    system call &quot;write&quot; just succeeds in writing and no error is given. This 
    design is quite logical and in consistent with the semantics of write call. 
    It is up to the application to decide whether this seemingly useless write 
    is an error or not. And I guess maybe the system needs to maintain &quot;write&quot; 
    as an atomic operation which is done without checking first and after write 
    is done system checks read's end. Then the signal is generated. 
    <table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
      <tr>
        <td class="head">sigpipe</td>
        <td class="head" align="right">2005-03-05</td>
      </tr>
      <tr>
        <td class="body" colSpan="2">It seemed odd to me that a write error 
        could not be produced in this situation. After all, if there is a 
        problem writing, then it should be just as easy to return a write error 
        as to generate a SIGPIPE. So I did a little digging and it appears that 
        a write error IS returned when you try to write to a pipe that has been 
        closed at the other end. Specifically, it is the EPIPE error. So an 
        error AND a SIGPIPE signal are generated. I did a quick test and it is 
        true that a SIGPIPE signal and an EPIPE error are returned. We normally 
        don't see the EPIPE error because the default action of the SIGPIPE 
        handler is to terminate the program. <br>
        <br>
        So why is there a SIGPIPE signal and an EPIPE error? I'm not sure. It 
        has been suggested that SIGPIPE is there only to force immediate 
        termination in sloppy programs that don't do proper error checking on 
        the write. But, surely, there's a better reason than that since this 
        could be true of other calls as well.<br>
        <br>
        Dr Eavis </td>
      </tr>
    </table>
    <table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
      <tr>
        <td class="head"><a name="habit"></a>A little supplementary point</td>
        <td class="head" align="right">2005-03-05</td>
      </tr>
      <tr>
        <td class="body" colSpan="2">I quick test again and find a little 
        interesting thing. For those sloppy programmer, the write error wouldn't 
        appear. That is, if the programmer forget to close the &quot;read&quot; end at his 
        side, even the other process closes the &quot;read&quot; end there is no write 
        error or SIGPIPE signal at all. The reason is quite interesting and also 
        a kind of intelligent design. When a pipe is created, there is two 
        read's and two write's. By convention one read and one write end should 
        be closed. When the &quot;THIRD&quot; one is closed, it must be the read ends at 
        the other side. Only at this moment, there is write error created at 
        attempted writing. i.e. If the programmer is sloppy and forget to closes 
        his &quot;read&quot; end, even the other process correctly closes both his read 
        and write channel, he still doesn't get a write error. Because when the 
        programmer's read's channel is still open, the system assumes he wants 
        to communicate with himself. So, the good programming habit is always 
        closes the read channel which you wouldn't use. By doing this, you will 
        get an error when writing if the reader closes his reading end. <br>
        <br>
        Good programming habit always benefits.
        <table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
          <tr>
            <td class="head">If you are the good-habit programmer</td>
            <td class="head" align="right">2005-03-05</td>
          </tr>
          <tr>
            <td class="body" colSpan="2">even if the other process is a sloppy 
            programmer who always forgets to close his &quot;write&quot; end before he 
            prepares his reading, you still have chance to grasp the write error 
            if you remember to close your &quot;read&quot; before writing. That is when 
            the other process only closes his &quot;read&quot; without closing his 
            &quot;write&quot;, you will get write error when writing. Because by closing 
            your &quot;read&quot; channel, you already indicate to system that you are 
            attempted to _write_ and pipe system call will try to check if the 
            read channle at the other end is open or not. <br>
            <br>
            If you don't give enough infomation to system, system have no idea 
            whether you want to read or write to pipe. </td>
          </tr>
        </table>
        <p>&nbsp;</td>
      </tr>
    </table>
    <p>&nbsp;</td>
  </tr>
</table>

<p>&nbsp;</p>

<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">Error with pow</td>
    <td class="head" align="right">2005-03-05</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">I got this error from gcc:<br>
    <br>
    /tmp/ccgWholx.o(.text+0x307): In function `Set_game_file_as_empty':<br>
    <br>
    : undefined reference to `pow'<br>
    <br>
    The API for the pow function is this:<br>
    <br>
    #include
    <math.h>&lt;math.h&gt;<br>
    <br>
    double pow(double x, double y);<br>
    <br>
    Obviously, I included math.h and placed non-constant double variables as 
    parameter (and converted the return value to 'int').<br>
    <br>
    Any inspirations as to the possible origins for this error? </math.h>
    <table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
      <tr>
        <td class="head">pow problem</td>
        <td class="head" align="right">2005-03-05</td>
      </tr>
      <tr>
        <td class="body" colSpan="2">If you see this error, it's generally 
        because you must explicitly include the math library during the link 
        phase. If you just have one source file this might look like:<br>
        <br>
        gcc mysource.c -lm -o myfile.exe<br>
        <br>
        The -lm switch (no space between them)means that gcc should include the 
        math library when linking.<br>
        <br>
        Dr Eavis </td>
      </tr>
    </table>
    <p>&nbsp;</td>
  </tr>
</table>

<p>&nbsp;</p>

<p><font color="#FF0000"><a name="gdb"></a>And this is for my personal reminder 
of debugging for another running process by using &quot;attach&quot; in GDB</font></p>

<p>1. When the other process ID is available either by tracing or without 
tracing, you can attach the process by using GDB -p [pid] [exefile].</p>

<p>2. It is wrong to kill the debugged process within GDB because it may closes 
all processes including children. Instead you should open another GDB process 
and debug over there. GDB is magic!&nbsp; </p>

<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">Killing each dead player is annoying</td>
    <td class="head" align="right">2005-03-08</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">As we are all users to this Linux server &quot;alamanni&quot;, 
    I noticed there are increasing number of &quot;dead player&quot; program left in the 
    server. And it is really an annoying pain to &quot;kill -9&quot; each &quot;player.exe&quot; one 
    by one when you are debugging your program. My little experience is just 
    call &quot;atexit&quot; function and register a simple handler which sends SIGQUIT to 
    all children programs by specifying parameter of pid=0. Therefore whenever 
    you shut down your &quot;tournament.exe&quot;, you can be sure there is no dead child 
    floating in server.
    <table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
      <tr>
        <td class="head">another option</td>
        <td class="head" align="right">2005-03-09</td>
      </tr>
      <tr>
        <td class="body" colSpan="2">Another, perhaps simpler option, is to use 
        the killall function. killall can be called from the command line and 
        can be used to send a signal to all programs with a given name (only the 
        ones you own). So &quot;killall player.exe&quot; would kill all of those processes 
        at once.<br>
        <br>
        Dr Eavis </td>
      </tr>
    </table>
    <p>&nbsp;</td>
  </tr>
</table>
<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">STDOUT_FILENO and stdout</td>
    <td class="head" align="right">2005-03-07</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">Professor, I thought I observed something, but 
    I am still not very sure. And I need your justification.<br>
    <br>
    1. The testing example I wrote is a bit long, so I only give the idea.<br>
    <br>
    2. When I use &quot;dup2&quot; to make writing end of pipe pointing to STDOUT_FILENO, 
    I originally expect the file object &quot;stdout&quot; is also modified to direct to 
    my pipe. But it seems not. i.e. After I called dup2(fds[1], STDOUT_FILENO) , 
    whenever I call write(STDOUT_FILENO, buf, buf_len), I am writing to the pipe 
    instead of original I/O. But what if I call fputs(buf, stdout)? I expected 
    it should be same as &quot;write&quot; call which is directed to pipe. But it seems 
    not.<br>
    <br>
    3. If file library call like fputs etc is implemented by &quot;write&quot; syscall, 
    they logically should be directed after I dup2 the STDOUT_FILENO, right?<br>
    <br>
    Thank you for your time.
    <table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
      <tr>
        <td class="head">Sorry, forget about this stupid question</td>
        <td class="head" align="right">2005-03-07</td>
      </tr>
      <tr>
        <td class="body" colSpan="2">With another check, I found out this is 
        only due to the fact that I forget &quot;fflush(stdout)&quot; and the textbook 
        already has such implication in the example. I am sorry to bother you.<br>
        <br>
        Thanks anyway. </td>
      </tr>
    </table>
    <p>&nbsp;</td>
  </tr>
</table>

<p>The reason for you to link &quot;math&quot; library is the same as &quot;pthread&quot;. But 
recall that usually gcc should give &quot;unresolved function&quot; after linking if the 
implementation of a function used is not supplied. However, when you compile 
program which uses functions from &quot;math.h&quot; or &quot;pthread.h&quot;, gcc just finishes 
fine without giving linking error. But the program won't run. There is two 
questions here. 1. Why no error is given in compiling stage? 2. Why should you 
have to link them by yourself?</p>

<p>The second question is easy since I guess these libraries are 
platform-specific. That is to say, different platform have its own 
implementation and the best way to deal with this problem is to make these 
library dynamic library so that these library interface can be made uniformal in 
different platform. But the first question I have no clue at all. I guess there 
must be some compiler directive suppressing gcc to link functions in dynamic 
library. But I don't know what it is or whether this is the answer. I noticed 
there is a key word &quot;__THROW&quot; at end of each pthread function. Is it the one? I 
think it is not since in &quot;math.h&quot; I didn't find similar one.</p>

<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head"><a name="thread1"></a>Thread test 1</td>
    <td class="head" align="right">2005-03-10</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">In class, some guy suggested to pass &quot;main&quot; as 
    parameter in &quot;pthread_create&quot;. Actually it works because whenever you pass 
    as parameter is simply the address of a function, or address in &quot;text&quot; 
    segment. However, gcc is also responsibly pointed out that &quot;main&quot; is not 
    match with prototype of parameter by warning. And I tried to run the 
    program, it did works. How can I be sure the thread succeed? I add printf at 
    the beginning of &quot;main&quot; which prints the first argument in main. <br>
    <br>
    By the way, it seems there is an upperlimit 5 for creating threads. At least 
    this happens in linux server &quot;alamanni&quot; by giving error of &quot;resource 
    temporarily unavailable&quot;.<br>
    <br>
    However, when I recompile and run the same program in &quot;sunset&quot; which is said 
    to be Unix server, there is no limit at all. Only that when I try to test 
    the limit by specifying the number of threads to be 100000, there is 
    occasional error of &quot;not enough space&quot; which makes perfect sense since each 
    thread runs up a part of 4G byte virtual memory space of process. <br>
    <br>
    Based on above observation, my conclusion is that Linux threads are indeed 
    kernal-supported threads which can be treated as a kind of hardware 
    resource. While Unix thread is purely user-support thread in which &quot;pthread&quot; 
    library is implemented purely by software. <br>
    <br>
    Am I right, professor? </td>
  </tr>
</table>

<p>&nbsp;</p>

<p><b><font color="#FF0000">Playing with pointers...(The following stuff is 
purely for personal reminder. It may contain contents of ambiguity and 
incorrectness. View's</font></b><font color="#FF0000"><b> discretion is 
suggested.)</b></font></p>

<pre>Look at code following and do you really understand &quot;pass-by-pointer&quot;? I think I do, but I don't.</pre>
<pre>1. All variable is just an alias of memory address.</pre>
<pre>2. Pass-by-pointer just passes the address and see following prototype: void foo(char* ptr);</pre>
<pre>int main()</pre>
<pre>{</pre>
<pre>	char* onlyPtr;</pre>
<pre>	foo(onlyPtr);//here you pass a wild pointer and you are lucky if program crashes.</pre>
<pre>}</pre>
<pre>3. What compiler does is to create a temporary variable of char* which has the same value of your parameter.</pre>
<pre>i.e.    char myCh;</pre>
<pre>	foo(&amp;myCh); //a temporary char* variable created to have value of &amp;myCh which is an address of itself.</pre>
<pre>4. What should I say about this simple question? I sometimes boast myself as a decent C/C++ programmer whose basic</pre>
<pre>instinct is the handling of pointers. However, I found out I was confused a bit with &quot;passing-by-pointer&quot; mode.</pre>
<pre>Let's keep one simple thing in our mind because all others are not absolutely necessary:</pre>
<pre><b><font color="#FF0000"><a name="value"></a>There is ONE AND ONLY ONE MODE IN C, &quot;passing-by-value&quot;, nothing more and nothing less.</font></b></pre>
<pre>5. Pay attention that a memory address is passed to the function and you can manage with the address whatever you </pre>
<pre>like to do. When the function returns, you can retrieve the address stored in the contents in the address. I can</pre>
<pre>even pass the address of an integer which happens to have same length of an address, based on current 32bit address</pre>
<pre>architecture.</pre>
<pre>#include &lt;stdlib.h&gt;
 
#define PtrSize sizeof(char*)
char* createBuf(char* ptr);

int main()
{
        char* array;
        char ptr[PtrSize];
        char*temp=NULL;   
        array=createBuf(ptr);
        printf(&quot;malloc contents : %s\n&quot;, array);
        //temp=(char*)(*ptr);
        //strncpy(temp, *((char**)ptr), sizeof(char*));
        printf(&quot;and from ptr is %s\n&quot;,*((char**)ptr)); 
        
        return 0;
}
        
char* createBuf(char* ptr)
{
        char* buf;
        int i;
        buf=(char*) malloc(500*sizeof(char));
        for (i=0; i&lt;26; i++)
        {
                buf[i]='a'+i;
        }
        buf[i]='\0';
        *((char**)ptr)=buf;
        return buf;
}
        
</pre>

<p><b><font color="#FF0000" size="4"><a name="synchronization"></a>
synchronization---revisited</font></b></p>

<p>Actually there is little new about this synchronization test except that I am 
now using Linux pthread library with conditional variable instead of 
busy-waiting-style of polling. It is almost exactly a re-make of Dr. Probst 
array increment in comp346. Now I begin to understand some of his lectures. I 
really regret what I commented on him before. He is a good professor and I am 
stupid at that time since my view was as narrow as what I could see.</p>

<p>Conditional waiting is really a big leap from &quot;polling-style&quot; busy waiting 
and there is one thing worth bearing in mind: you need to unlock the mutex when 
you exit the conditional variable because &quot;pthread_cond_wait&quot; implicitly 
acquires the mutex for you and it is always your job to unlock it. Another small 
issue is that you would be better to call &quot;pthread_cond_broadcast&quot; instead of &quot;pthread_cond_signal&quot; 
unless you are sure about the sequence of how waiting threads are woken up.</p>

<pre>#include &lt;pthread.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;time.h&gt;
#define Max_Threads 10

pthread_t threads[Max_Threads];

pthread_cond_t cond=PTHREAD_COND_INITIALIZER;

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

int array[Max_Threads]={0,1,2,3,4,5,6,7,8,9};

int sequence[Max_Threads]={0,1,2,3,4,5,6,7,8,9};

void* func(void* arg);

void printArray();

void randomSequence();

int main()
{
	int i, *value;
	srand(time(0));
	printArray();
	randomSequence();
	for (i=0; i&lt;Max_Threads; i++)
	{
		if (pthread_create(&amp;threads[sequence[i]], NULL, func,&amp;sequence[i]))
		{
			printf(&quot;create error\n&quot;);
		}
		else
		{
			printf(&quot;threas[%d] is created\n&quot;, sequence[i]);
		}
	}
	for (i=0; i&lt;Max_Threads; i++)
	{
		if (pthread_join(threads[i], (void**)(&amp;value)))
		{
			printf(&quot;join error&quot;);
		}
		printf(&quot;thread no.%d return with value=%d\n&quot;, i,*value);
	}
	printf(&quot;let me show you the array\n&quot;);
	printArray();
}

void randomSequence()
{
	int i,j, hold;
	for (i=0; i&lt;Max_Threads; i++)
	{
		j=rand()%10;
		hold=sequence[i];
		sequence[i]=sequence[j];
		sequence[j]=hold;
	}
}

void printArray()
{
	int i;
	for (i=0; i&lt;Max_Threads; i++)
	{
		printf(&quot;array[%d]=%d,&quot;, i, array[i]);
	}
	printf(&quot;\n&quot;);
}


void* func(void* arg)
{
	int index;
	index=*((int*)arg);
	if (pthread_mutex_lock(&amp;mutex))
	{
		printf(&quot;mutex lock error&quot;);
	}
	if (index==0)
	{
		array[index]++;
		printf(&quot;threads[0] finished\n&quot;);
		if (pthread_cond_broadcast(&amp;cond))
		{
			printf(&quot;cond signal error&quot;);
		}
		if (pthread_mutex_unlock(&amp;mutex))
		{
			printf(&quot;unlock eeeror&quot;);
		}
	}
	else
	{
		while (array[index-1]!=index)
		{
			if (pthread_cond_wait(&amp;cond, &amp;mutex))
			{
				printf(&quot;cond lock error\n&quot;);
			}
		}
		array[index]++;
		printf(&quot;threads[%d] finishes job\n&quot;, index);
		if (pthread_cond_broadcast(&amp;cond))
		{
			printf(&quot;cond error&quot;);
		}
		if (pthread_mutex_unlock(&amp;mutex))
		{
			printf(&quot;unlock eeeror&quot;);
		}
	}
	return &amp;array[index];
}	
	
	</pre>

<p>
array[0]=0,array[1]=1,array[2]=2,array[3]=3,array[4]=4,array[5]=5,array[6]=6,array[7]=7,array[8]=8,array[9]=9,<br>
threas[3] is created<br>
threas[1] is created<br>
threas[6] is created<br>
threas[4] is created<br>
threas[0] is created<br>
threads[0] finished<br>
threads[1] finishes job<br>
threas[9] is created<br>
threas[7] is created<br>
threas[8] is created<br>
threas[2] is created<br>
threads[2] finishes job<br>
threads[3] finishes job<br>
threas[5] is created<br>
threads[4] finishes job<br>
thread no.0 return with value=1<br>
threads[5] finishes job<br>
thread no.1 return with value=2<br>
thread no.2 return with value=3<br>
thread no.3 return with value=4<br>
thread no.4 return with value=5<br>
threads[6] finishes job<br>
threads[7] finishes job<br>
threads[8] finishes job<br>
thread no.5 return with value=6<br>
thread no.6 return with value=7<br>
threads[9] finishes job<br>
thread no.7 return with value=8<br>
thread no.8 return with value=9<br>
thread no.9 return with value=10<br>
let me show you the array<br>
array[0]=1,array[1]=2,array[2]=3,array[3]=4,array[4]=5,array[5]=6,array[6]=7,array[7]=8,array[8]=9,array[9]=10,<br>
&nbsp;</p>

<table style="width: 663; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head" width="292"><a name="sleep"></a>The puzzle of sleep...</td>
    <td class="head" align="right" width="344">2005-03-25</td>
  </tr>
  <tr>
    <td class="body" colSpan="2" width="649">Dear professor, I extended a little 
    bit of your example in class to prove &quot;sleep&quot; call won't cause whole process 
    to sleep. Basically, I modified the pthread_attr to minimize the thread 
    stack size so that I can create maximum number of pthreads. <br>
    <br>
    And the program does exactly same job in your program: create as many as 
    possbile pthreads and assign a index number for each one, and each thread 
    sleep the number of seconds equal to its index number. Therefore all threads 
    just wake up one by one. <br>
    <br>
    This works all fine in our lab machine and sunset. But my question is just 
    they seems to be too much for &quot;kernel-support-thread&quot; because I tried 8000 
    threads in Linux machine and 20000 threads in &quot;sunset&quot; which is Unix. And I 
    cannot persuade myself that the Unix can support as many as 20,000 
    &quot;kernel-aware&quot; threads. Even in Linux, 8000 is too much for &quot;one-to-one&quot; 
    matching kernel thread. The following is the code I am using:<br>
    <br>
    #include &lt;pthread.h&gt;<br>
    <br>
    #include &lt;stdlib.h&gt;<br>
    <br>
    #include &lt;limits.h&gt;<br>
    <br>
    const int MaxThread=20000;<br>
    <br>
    void* run(void* arg);<br>
    <br>
    int main()<br>
    <br>
    {<br>
    <br>
    	pthread_t threads[MaxThread];<br>
    <br>
    	pthread_attr_t attribute;<br>
    <br>
    	int i;<br>
    <br>
    	pthread_attr_init(&amp;attribute);<br>
    <br>
    	//if (pthread_attr_setstacksize(&amp;attribute,PTHREAD_STACK_MIN))<br>
    <br>
    	if (pthread_attr_setstacksize(&amp;attribute,16384))<br>
    <br>
    	{<br>
    <br>
    		printf(&quot;set attribute error\n&quot;);<br>
    <br>
    	}<br>
    <br>
    	for (i=0; i&lt;MaxThread; i++)<br>
    <br>
    	{<br>
    <br>
    		if (pthread_create(&amp;threads[i], &amp;attribute, run,(void*)i))<br>
    <br>
    		{<br>
    <br>
    			printf(&quot;unable create threads&quot;);<br>
    <br>
    		}<br>
    <br>
    	}<br>
    <br>
    	sleep(MaxThread);<br>
    <br>
    	return 0;<br>
    <br>
    }	<br>
    <br>
    void* run(void* arg)<br>
    <br>
    {<br>
    <br>
    	int index=(int)arg;<br>
    <br>
    	char msg[40];<br>
    <br>
    	sprintf(msg, &quot;this is thread %d\n&quot;, index);<br>
    <br>
    	write(1, msg, strlen(msg));<br>
    <br>
    	sleep(index);<br>
    <br>
    	msg[strlen(msg)]='\0';<br>
    <br>
    	strcat(msg, &quot; wake up\n&quot;);<br>
    <br>
    	write(1, msg, strlen(msg));<br>
    <br>
    }<br>
    <br>
&nbsp;<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
      <tr>
        <td class="head">thread max</td>
        <td class="head" align="right">2005-03-25</td>
      </tr>
      <tr>
        <td class="body" colSpan="2">Actually, we discussed this in class at 
        some point. The maximum thread limit -particularly on Linux - is usually 
        not very high. Without adjusting the stack size, it may be as little as 
        a few hundred threads. If you reduce the stack size - as you've done 
        here - you'll be able to go higher. However, the pre-compiled pthread 
        limit (i.e., for the libraries themselves) is typically 1024. So you 
        won't be able to go any higher than this. Even if you could (by 
        re-compiling pthreads), you would run into user resource and/or system 
        limits that would likely prevent you from creating any more than a few 
        thousand threads (this would also be true of other OSes). There is no 
        chance that you could create 20000 threads, at least not without a lot 
        of recompilation, system administration, and perhaps more memory.<br>
        <br>
        Dr Eavis
        <table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
          <tr>
            <td class="head">I did succeed in running 20,000 threads</td>
            <td class="head" align="right">2005-03-25</td>
          </tr>
          <tr>
            <td class="body" colSpan="2">in &quot;susnset.cs.concordia.ca&quot; which is 
            unix. My question is like this:<br>
            <br>
            My program proves that each &quot;sleep&quot; call will NOT put whole process 
            to be sleeping, instead only put the calling thread to sleep. This 
            is a proof of &quot;kernel-support&quot; thread. But 20,000 kernel-support 
            thread seems unbelieveable to me since I assume kernel-supported 
            threads would be a precious resource and won't be arbitrarily as 
            many as user requests. <br>
            <br>
            Professor, can you justify this, please?<br>
            <br>
            By the way, the proof of each &quot;sleep&quot; call only put calling thread 
            to be asleep is exactly same as your demo example in class. Every 
            second, there is one thread wake up.<br>
            <br>
&nbsp;<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
              <tr>
                <td class="head">high thread count</td>
                <td class="head" align="right">2005-03-26</td>
              </tr>
              <tr>
                <td class="body" colSpan="2">It's quite unlikely that these are 
                all kernel supoorted threads. Remember that Solaris has 
                traditionally used a two-level, many-to-many threading model. It 
                multiplexes user created threads on top of a potentially smaller 
                number of kernel supported threads. This multi-plexing can be 
                done automatically based upon the characteristics of the 
                application. I suspect this is what you are seeing - thousands 
                of user-level threads but a small number of kernel supported 
                light weight processes. Unfortunately, I can't be sure since 
                Solaris doesn't provide a lot of free information about its 
                threading package.<br>
                <br>
                Keep in mind that user levels threads do not prevent blocking 
                calls like sleep from working properly. I said in class that 
                it's easy to do thread specific sleep calls with kernel 
                supported user threads since each thread is a schedulable kernel 
                entity. However, user level threads can also provide thread 
                specific blocking calls by providing new versions of the calls 
                with the threading libraries (and using some kind of wrapper 
                interface). It is complex but it can be done. So if user levels 
                threads are being used in your example, the sleep calls may 
                still work just fine.<br>
                <br>
                Finally, keep in mind that in the latest releases of Solaris, 
                Sun is apparently moving to the one-to-one model for threads. 
                I've run thread creation tests on a couple of Solaris machines 
                that I have access to and they can only create a couple of 
                thousand threads before failing.<br>
                <br>
                Dr Eavis
                <table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
                  <tr>
                    <td class="head">I also suspect they are kernel-aware</td>
                    <td class="head" align="right">2005-03-27</td>
                  </tr>
                  <tr>
                    <td class="body" colSpan="2">threads.<br>
                    <br>
                    1. To go extreme, I even tried 60,000 threads in &quot;Sunset&quot; 
                    which is Unix. And it works fine, maybe in Unix it is a 
                    &quot;hybrid-mode&quot; or &quot;many-to-many&quot; like soloris. But in Linux, 
                    about 8000 is the upper limit. Since book claims Linus is 
                    one-to-one, 8000 seems to be too many.<br>
                    <br>
                    2. User level thread can be made thread specific when 
                    blocking calls are made. This makes senses. But the call 
                    &quot;sleep&quot; is actually system call and I cannot see any wrapper 
                    function over it. (maybe pthread intercepts singal handler 
                    if &quot;sleep&quot; is implemented by &quot;alarm&quot; signal.) Still it is 
                    not very clear.<br>
                    <br>
                    3. Linux thread must be using process ID and is 
                    kernel-aware. In &quot;alamanni&quot; server, administrater limits the 
                    number of threads we can create. So, this is another proof 
                    that pthread is kernel-aware threads in Linux. The question 
                    is just is it possible for kernel to implement 8000 more 
                    kernel threads, based on &quot;one-to-one model&quot;? This is 
                    unbelieveable. <br>
                    <br>
                    4. It seems all proof has forced me to believe Linux does 
                    support more than 8000 kernel-aware threads. Is it right, 
                    sir?<br>
                    <br>
&nbsp;</td>
                  </tr>
                </table>
                </td>
              </tr>
            </table>
            </td>
          </tr>
        </table>
        </td>
      </tr>
    </table>
    </td>
  </tr>
</table>

<p>
<font color="#FF0000">My conclusion for above puzzle: </font></p>

<p>
I developed my own theory to explain above like this: 1. In &quot;unix&quot; which is 
actually &quot;soloris&quot; it is &quot;hybrid&quot; model. It means the kernel thread support 
unlimited user thread like &quot;thread-pool&quot;. Thereby I don't have any 
&quot;kernel-aware&quot; thread number limit in Unix. Whereas in Linux, it is &quot;one-to-one&quot; 
model and I do have a number limit for creating threads. </p>

<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head"><a name="mappedio"></a>why do I have to specify &quot;O_RDWR&quot;?</td>
    <td class="head" align="right">2005-03-30</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">In the example of book on page 412 which is 
    about &quot;mapped I/O&quot; and is also demoed in class, when we open both source and 
    target file we have to specify the open mode for each. It is very reasonable 
    for &quot;readonly&quot; for the source file since I only need to copy contents from 
    it. However, it is quite unexpected to specify &quot;read&amp;write&quot; or &quot;O_RDWR&quot; for 
    the target file since I only want to write contents into it.<br>
    <br>
    I tried to use &quot;O_WRONLY&quot; and I always run into error when &quot;mmap&quot; it into 
    memory with error message &quot;permission denied&quot;.<br>
    <br>
    Professor, is there any reason for this? Or any rationale about this &quot;read 
    and write&quot; instead of &quot;write only&quot;? </td>
  </tr>
</table>

<p>
&nbsp;</p>

<p><font color="#FF0000"><a name="wildwildwest"></a>I write all following 
testing program in a rather random style. Sometimes I just want to confirm a 
single idea which seems to be so trivial for most of us. And of course most of 
them have a rather blurred purpose and even cannot be understood by myself 
afterwards.</font></p>

<p><font color="#0000FF">1. Broadcast test: I want to confirm that 
pthread_cond_broad only wakes up those threads who already associated with the 
conditional variable. (This is insane! Because it is already stated very clearly 
both in manual page and textbook. However, I give it a try.)</font></p>

<p>Also I practice the idea of multiple condition which I have an impression of 
being discussed by Dr. Probst. I didn't have a ready mind at that time.</p>

<pre>#include &lt;pthread.h&gt;
#include &lt;stdlib.h&gt;


#define ThreadNumber 16

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t evencond=PTHREAD_COND_INITIALIZER, oddcond=PTHREAD_COND_INITIALIZER;
int choice=-1;
int counter;

void initialize();

void* run(void* arg);

int main()
{
	initialize();
	printf(&quot;sleep(2)\n&quot;);
	sleep(2);
	choice=getpid()%2;
	printf(&quot;choice=%d\n&quot;, choice);
	if (choice%2==0)
	{
		if (pthread_cond_signal(&amp;oddcond))
		{
			perror(&quot;signal error from main&quot;);
		}			
	}
	else
	{
		if (pthread_cond_signal(&amp;evencond))
		{
			perror(&quot;signal error from main&quot;);
		}
	}
	sleep(2);		
	return 0;
}

void* run(void* arg)
{
	//while (1)
	{
		if (pthread_mutex_lock(&amp;mutex))
		{
			perror(&quot;mutex error&quot;);
		}
		while (choice&lt;0)
		{
			if ((int)arg%2==0)//even
			{
				if (pthread_cond_wait(&amp;evencond, &amp;mutex))
				{
					perror(&quot;cond lock error&quot;);
				}
			}
			else
			{
				if (pthread_cond_wait(&amp;oddcond, &amp;mutex))
				{
					perror(&quot;cond error&quot;);
				}
			}
		}
		while (choice!=(int)arg%2)
		{
			printf(&quot;thread#%d is running\n&quot;, (int)arg);
			if ((int)arg%2==0)
			{
				if (pthread_cond_broadcast(&amp;oddcond))
				{
					perror(&quot;broadcast error&quot;);
				}
				if (pthread_cond_wait(&amp;evencond, &amp;mutex))
				{
					perror(&quot;cond error&quot;);
				}
			}
			else
			{
				if (pthread_cond_broadcast(&amp;evencond))
				{
					perror(&quot;broadcast error&quot;);
				}
				if (pthread_cond_wait(&amp;oddcond, &amp;mutex))
				{
					perror(&quot;cond error&quot;);
				}
			}
		}
		if ((int)arg%2==0)
		{
			if (pthread_cond_signal(&amp;evencond))
			{
				perror(&quot;signal error&quot;);
			}
		}
		else
		{
			if (pthread_cond_signal(&amp;oddcond))
			{
				perror(&quot;signal error&quot;);
			}
		}
		printf(&quot;thread#%d is finished\n&quot;, (int)arg);
		if (pthread_mutex_unlock(&amp;mutex))
		{
			perror(&quot;mutex unlock error&quot;);
		}
		
	}
}

void initialize()
{
	int i;
	pthread_t tid;
	for (i=0; i&lt;ThreadNumber; i++)
	{
		if (pthread_create(&amp;tid, NULL, run, (void*)i))
		{
			perror(&quot;create error&quot;);
		}
	}
}</pre>

<p>2. write test: In this little weird test, I want to run multiple process 
which has no relation at all. (i.e. not by fork) And ask them to write to same 
file with different contents at almost same time. Obviously the file can only be 
a mess. </p>

<pre>#include &lt;stdlib.h&gt;
#include &lt;signal.h&gt;
#include &lt;stdio.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;sys/stat.h&gt;

#define BufferSize 1024
#define WriteNumber 16
#define WriteSize BufferSize/WriteNumber

char buf[BufferSize];

void initialize(char ch);
void handler(int no);

int fd, count=0;

int main(int argc, char* argv[])
{
	sigset_t maskset, zeroset;
	sigemptyset(&amp;zeroset);
	sigemptyset(&amp;maskset);
	sigaddset(&amp;maskset, SIGUSR1);
	
	if (argc!=3)
	{
		printf(&quot;usage: writetest.exe filename contents&quot;);
		exit(0);
	}
	initialize(argv[2][0]);
	if (sigprocmask(SIG_BLOCK, &amp;maskset, NULL)&lt;0)
	{
		perror(&quot;sigprocmask error&quot;);
	}
	if ((fd=open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IXUSR))&lt;0)
	{
		perror(&quot;open error&quot;);
	}
	if (lseek(fd, 0, SEEK_SET)&lt;0)
	{
		perror(&quot;lseek error&quot;);
	}
	if (signal(SIGUSR1, handler)==SIG_ERR)
	{
		perror(&quot;signal error&quot;);
	}
	while (count&lt;WriteNumber)
	{
		sigsuspend(&amp;zeroset);
	}
	return 0;
}

void handler(int no)
{
	if (write(fd, buf+count*WriteSize, WriteSize)!=WriteSize)
	{
		perror(&quot;write error&quot;);
	}
	else
	{
		count++;
	}
}

void initialize(char ch)
{
	int i;
	for (i=0; i&lt;BufferSize; i++)
	{
		buf[i]=ch+i%10;
	}
}

<font color="#0000FF">The above program takes two parameters: file name and symbols to be written into file.</font></pre>
<pre><font color="#0000FF">The following is the running script:</font></pre>
<font SIZE="2">
<p>./writetest.exe writeresult.txt 0 &amp;</p>
<p>./writetest.exe writeresult.txt A &amp;</p>
<p>./writetest.exe writeresult.txt a &amp;</p>
<p><font color="#0000FF">And another script continually sends signal to all 
three running processes:</font></p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>kill -USR1 15038</p>
<p>kill -USR1 15037</p>
<p>kill -USR1 15039</p>
<p>sleep 1</p>
<p>&#12288;</p>
<p><font color="#0000FF">3. question 8 test: In assignment, we are asked a 
question about mapped I/O. It is said that assume one process maps a file into 
memory and another process just use system write to write to the file at almost 
same time, what would happen? I really don't know the answer. Nor do I after 
this test. </font></p>
<pre>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;signal.h&gt;
#include &lt;errno.h&gt;
#include &lt;sys/mman.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;fcntl.h&gt;

#define BufferSize 512

char buf[BufferSize];

void initialize(char* fileName);
void handler(int no);

int fd;

int main(int argc, char* argv[])
{
	if (argc!=2)
	{
		printf(&quot;usage: question8.exe filename\n&quot;);
		exit(0);
	}
	initialize(argv[1]);
	return 0;
}


void initialize(char* fileName)
{
	int i;
	pid_t pid;
	char* ptr;
	char endChar=' ';
	if ((fd=open(fileName, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR))&lt;0)
	{
		perror(&quot;open error\n&quot;);
	}
	if ((pid=fork())==0)
	{
		for (i=0; i&lt;BufferSize; i++)
		{
			buf[i]='0'+i%10;
		}
		if (signal(SIGUSR1, handler)==SIG_ERR)
		{
			perror(&quot;signal error\n&quot;);
		}
		pause();
	}
	else
	{
		for (i=0; i&lt;BufferSize; i++)
		{
			buf[i]='A'+i%10;
		}

		if (lseek(fd, BufferSize-1, SEEK_SET)&lt;0)
		{
			perror(&quot;lseek error&quot;);
		}
		if (write(fd, &amp;endChar, 1)!=1)
		{
			perror(&quot;write end of file error\n&quot;);
		}
		if (lseek(fd, 0, SEEK_SET)&lt;0)
		{
			perror(&quot;seek error\n&quot;);
		}	
		if ((ptr=mmap(0, BufferSize, PROT_WRITE, MAP_SHARED, fd, 0))==(caddr_t)(-1))
		{
			perror(&quot;map error\n&quot;);
		}
		sleep(1);
		if (kill(pid, SIGUSR1)&lt;0)
		{
			perror(&quot;kill error&quot;);
		}
		memcpy(ptr, buf, BufferSize);
		munmap(ptr, BufferSize);
		if (wait(&amp;i)&lt;0)
		{
			perror(&quot;wait error\n&quot;);
		}
	}
}

void handler(int no)
{
	if (write(fd, buf, BufferSize)!=BufferSize)
	{
		perror(&quot;sys write error\n&quot;);
	}
}	</pre>
<p>&nbsp;</p>
<p><font color="#0000FF">4. exit test: This is a little bit malicious program 
though it doesn't work. I want to register &quot;main&quot; in &quot;atexit&quot; call so that it 
never quits. Unfortunately my little plot for &quot;Undead Program&quot; doesn't work 
under &quot;kill signal&quot;. I guess &quot;kill signal&quot; just doesn't bother to call &quot;exit&quot;. 
Instead just call &quot;_exit&quot;.</font></p>
<p><font color="#0000FF">Later I want to scan all process ID to try to close 
them in server and of course scan all signals for each process which I can 
access. The only result is that I &quot;successfully&quot; killed myself. :) Naughty time 
is over.</font></p>
<pre>#include &lt;stdlib.h&gt;
#include &lt;signal.h&gt;
#include &lt;errno.h&gt;

void handle(int no);

int main()
{
	int no;
	pid_t pid;
	for (pid=1; pid&lt;65534; pid++)
	{
		if (kill(pid, SIGKILL)&lt;0)
		{
			perror(&quot;won't work\n&quot;);
		}
		else
		{

			for (no=0; no&lt;64; no++)
			{
				if (signal(no, handle)==SIG_ERR)
				{
					perror(&quot;signal error\n&quot;);
				}
			}
		}
	}
	printf(&quot;I am alive\n&quot;);
	sleep(1);
	if (atexit(main))
	{
		perror(&quot;atexit error&quot;);
	}
	return 0;
}


void handle(int no)
{
	abort();
}</pre>
<pre>&nbsp;</pre>
<pre>	<a name="sigchld"></a> <b><font color="#FF0000">signal is essentially bitmap and counting won't guarantee for all children's SIGCHLD signal</font></b>
</pre>
<p>The problem is like this:</p>
<font FACE="Arial">
<p ALIGN="LEFT"><font color="#0000FF">We have a parent process that generates a 
number of child processes. The</font></p>
<p ALIGN="LEFT"><font color="#0000FF">child processes will run for a very long 
time and the parent needs to continue</font></p>
<p ALIGN="LEFT"><font color="#0000FF">processing other things (the parent will 
run forever). We don’t want to create</font></p>
<p ALIGN="LEFT"><font color="#0000FF">zombies with these children when they 
finally end but we can’t just use a “fork</font></p>
<p ALIGN="LEFT"><font color="#0000FF">and wait” combination in the parent since 
this will prevent the parent from</font></p>
<p ALIGN="LEFT"><font color="#0000FF">doing its other processing. We could use a 
non-blocking waitpid call but then</font></p>
<p ALIGN="LEFT"><font color="#0000FF">we would have to keep checking (i.e., 
polling) to find out when the children</font></p>
<p ALIGN="LEFT"><font color="#0000FF">ended. So how can we prevent zombies (or 
at least get rid of them quickly) in</font></p>
<p ALIGN="LEFT"><font color="#0000FF">this situation?</font></p>
<b>
<p ALIGN="LEFT">Answer</b>: Unfortunately, the wording in this question was not 
as precise as it</p>
<p ALIGN="LEFT">should have been. Specifically, I wanted you to provide a 
solution in which the</p>
<p ALIGN="LEFT">parent knew exactly when a child finished and could take some 
action if</p>
<p ALIGN="LEFT">necessary. But I didn’t say that so there are really two 
acceptable answers.</p>
<p ALIGN="LEFT">The “proper” one is below:</p>
<p ALIGN="LEFT">One of the fundamental UNIX signals is SIGCLD (or SIGCHLD). When 
a child</p>
<p ALIGN="LEFT">process terminates, a SIGCLD signal is automatically sent to the 
parent</p>
<p ALIGN="LEFT">process. Unlike most other signals, the default action is to 
ignore this signal.</p>
<p ALIGN="LEFT">However, we can use it to “reap” dead child processes by 
creating a SIGCLD</p>
<p ALIGN="LEFT">signal handler in the parent. When this signal is received, the 
signal handler</p>
<p ALIGN="LEFT">can simply execute a wait() call to permit the resources of the 
child to be</p>
<p ALIGN="LEFT">reclaimed (a truly robust version may be a little more complex 
than this).</p>
<b>
<p ALIGN="LEFT">Alternate answer</b>: We can call fork twice so that the parent 
creates a child</p>
<p ALIGN="LEFT">and then this child creates another child. When the first child 
exits, the second</p>
<p ALIGN="LEFT">child is inherited by init and will be cleaned up whenever it 
finishes. The</p>
<p ALIGN="LEFT">original parent does a wait for its first child and reaps it as 
soon as it exits.</p>
<p ALIGN="LEFT">The parent can then keep on going since it has no more direct 
children.</p>
<p ALIGN="LEFT"><font color="#FF0000">My idea is like this:</font></p>
<table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
  <tr>
    <td class="head">About theory assignment3 no.8</td>
    <td class="head" align="right">2005-04-12</td>
  </tr>
  <tr>
    <td class="body" colSpan="2">Professor,<br>
    <br>
    I am reviewing the old assignment and think assignment3, question 8 is not 
    perfect. Since signal essentially is just kept as bitmap in each process, 
    accumulated signal will only be counted once. Then by &quot;counting&quot; signal &quot;SIGCHLD&quot; 
    is not a reliable way to prevent child process from becoming zombies. i.e. 
    when parent process is blocked or booted off from cpu for context switch, 
    more than one child exit will only generate one SIGCHILD signal to parent 
    process which is just one bit flipped. So, there are big chances that many 
    died children processes actually cannot be &quot;waited&quot;. The following is the 
    running result of my test program and along with it is a snap from &quot;ps -A&quot; 
    from other terminal to prove that many children are indeed zombies:<br>
    <br>
    <font color="#FF0000">running result of test program, please note that only 
    a few of died children are captured by &quot;wait&quot;:</font><br>
    <br>
    [root@sec05 mytest]# gcc -g sigchildtest.c -o sigchildtest.exe<br>
    <br>
    [root@sec05 mytest]# ./sigchildtest.exe<br>
    <br>
    child 19090 sleep 1 and dies<br>
    <br>
    child 19091 sleep 1 and dies<br>
    <br>
    child 19092 sleep 1 and dies<br>
    <br>
    child 19093 sleep 1 and dies<br>
    <br>
    child 19094 sleep 1 and dies<br>
    <br>
    child 19095 sleep 1 and dies<br>
    <br>
    child 19096 sleep 1 and dies<br>
    <br>
    child 19097 sleep 1 and dies<br>
    <br>
    child 19098 sleep 1 and dies<br>
    <br>
    child 19099 sleep 1 and dies<br>
    <br>
    child 19090 dies with status of 0<br>
    <br>
    child 19091 dies with status of 256<br>
    <br>
    child 19092 dies with status of 512<br>
    <br>
    child 19093 dies with status of 768<br>
    <br>
    <font color="#FF0000">And snap shot from &quot;ps&quot;:</font><br>
    <br>
    19089 pts/17 00:00:00 sigchildtest.ex<br>
    <br>
    19094 pts/17 00:00:00 sigchildtest.ex
    <defunct><br>
    <br>
    19095 pts/17 00:00:00 sigchildtest.ex
    <defunct><br>
    <br>
    19096 pts/17 00:00:00 sigchildtest.ex
    <defunct><br>
    <br>
    19097 pts/17 00:00:00 sigchildtest.ex
    <defunct><br>
    <br>
    19098 pts/17 00:00:00 sigchildtest.ex
    <defunct><br>
    <br>
    19099 pts/17 00:00:00 sigchildtest.ex
    <defunct><br>
    <br>
    The following are the test program:<br>
&nbsp;</defunct></defunct></defunct></defunct></defunct></defunct><pre>#include &lt;signal.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;stdlib.h&gt;

void handler(int no);

int main()
{
	int i;
	if (signal(SIGCHLD,handler)==SIG_ERR)
	{
		printf(&quot;signal error&quot;);
	}
	for (i=0; i&lt;10; i++)
	{
		if (fork()==0)
		{
			while (1)
			{
				printf(&quot;child %d sleep %d and dies\n&quot;, getpid(), 1);
				sleep(1);
				//if (i%2==0)
				{
					exit(i);
				}
			}		
		}
	}
	while (1)
	{
		sleep(5);
	}
	return 0;
}



void handler(int no)
{
	pid_t pid;
	int status;
	if ((pid=wait(&amp;status))&lt;0)
	{
		printf(&quot;wait error&quot;);
	}
	else
	{
		printf(&quot;child %d dies with status of %d\n&quot;, pid, status);
	}
}
		</pre>
    <table style="width: 500px; border-collapse: collapse; border-spacing: 0px; border: 1px solid #000000">
      <tr>
        <td class="head">wait and sigchild</td>
        <td class="head" align="right">2005-04-12</td>
      </tr>
      <tr>
        <td class="body" colSpan="2">Your analysis is correct. However, you'll 
        note in my answer that I said &quot;a truly robust version may be a little 
        more complex than this&quot;. In actual fact, we do not use a simple wait 
        call. Instead, we use a waitpid call in a loop. The arguments to waitpid 
        are set so that it waits for any process (not a specific one) and that 
        it is non-blocking. If run this way, the waitpid will loop inside the 
        signal handler, cleaning up ONE OR MORE children that have ended.<br>
        <br>
        Perhaps I should have put this full explanation in the solution 
        sheet...but I just wanted to see if students could figure out the basic 
        idea.<br>
        <br>
        Dr Eavis </td>
      </tr>
    </table>
    </td>
  </tr>
</table>
</font>
</font>

<p><a name="difference"></a><b><font color="#FF0000">The difference need to be 
made between c and c++</font></b></p>

<table width="300" border="1">
  <tr>
    <td width="50%" bgColor="silver"><b>ANSI-C++</b></td>
    <td width="50%" bgColor="silver"><b>ANSI-C</b></td>
  </tr>
  <tr>
    <td><tt>&lt;cassert&gt;</tt></td>
    <td><tt>&lt;assert.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;cctype&gt;</tt></td>
    <td><tt>&lt;ctype.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;cerrno&gt;</tt></td>
    <td><tt>&lt;errno.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;cfloat&gt;</tt></td>
    <td><tt>&lt;float.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;ciso646&gt;</tt></td>
    <td><tt>&lt;iso646.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;climits&gt;</tt></td>
    <td><tt>&lt;limits.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;clocale&gt;</tt></td>
    <td><tt>&lt;locale.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;cmath&gt;</tt></td>
    <td><tt>&lt;math.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;csetjmp&gt;</tt></td>
    <td><tt>&lt;setjmp.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;csignal&gt;</tt></td>
    <td><tt>&lt;signal.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;cstdarg&gt;</tt></td>
    <td><tt>&lt;stdarg.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;cstddef&gt;</tt></td>
    <td><tt>&lt;stddef.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;cstdio&gt;</tt></td>
    <td><tt>&lt;stdio.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;cstdlib&gt;</tt></td>
    <td><tt>&lt;stdlib.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;cstring&gt;</tt></td>
    <td><tt>&lt;string.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;ctime&gt;</tt></td>
    <td><tt>&lt;time.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;cwchar&gt;</tt></td>
    <td><tt>&lt;wchar.h&gt;</tt></td>
  </tr>
  <tr>
    <td><tt>&lt;cwtype&gt;</tt></td>
    <td><tt>&lt;wtype.h&gt;</tt></td>
  </tr>
</table>

<p>&nbsp;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;           
&nbsp;&nbsp;&nbsp; <a href="stack.htm">      







                       <img src="picture/back.gif" style="border: medium none" alt="back.gif (341 bytes)" width="32" height="35"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  
<a href="index.htm">
<img src="picture/up.gif" style="border: medium none" alt="up.gif (335 bytes)" width="35" height="32"></a>       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<a href="detective.htm">
<img src="picture/next.gif" style="border: medium none" alt="next.gif (337 bytes)" width="32" height="35">          


</a>          


</p>

</body>

</html>