100% found this document useful (4 votes)
63 views

Operating Systems 3rd Edition Nutt Solutions Manualinstant download

The document provides links to various solutions manuals and test banks for multiple editions of textbooks, including 'Operating Systems 3rd Edition' by Nutt and others. It includes detailed exercises and solutions related to high-level synchronization and interprocess communication. Additionally, it discusses concepts such as semaphores, monitors, condition variables, and examples of process communication in operating systems.

Uploaded by

abanoruihua
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (4 votes)
63 views

Operating Systems 3rd Edition Nutt Solutions Manualinstant download

The document provides links to various solutions manuals and test banks for multiple editions of textbooks, including 'Operating Systems 3rd Edition' by Nutt and others. It includes detailed exercises and solutions related to high-level synchronization and interprocess communication. Additionally, it discusses concepts such as semaphores, monitors, condition variables, and examples of process communication in operating systems.

Uploaded by

abanoruihua
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 35

Operating Systems 3rd Edition Nutt Solutions

Manual pdf download

https://testbankfan.com/product/operating-systems-3rd-edition-
nutt-solutions-manual/
We believe these products will be a great fit for you. Click
the link to download now, or visit testbankfan.com
to discover even more!

Operating Systems 3rd Edition Nutt Test Bank

https://testbankfan.com/product/operating-systems-3rd-edition-
nutt-test-bank/

Operating Systems 3rd Edition Deitel Solutions Manual

https://testbankfan.com/product/operating-systems-3rd-edition-
deitel-solutions-manual/

Operating Systems Design And Implementation 3rd Edition


Tanenbaum Solutions Manual

https://testbankfan.com/product/operating-systems-design-and-
implementation-3rd-edition-tanenbaum-solutions-manual/

Microeconomic Theory Basic Principles and Extensions


12th Edition Nicholson Solutions Manual

https://testbankfan.com/product/microeconomic-theory-basic-
principles-and-extensions-12th-edition-nicholson-solutions-
manual/
RF Microelectronics 2nd Edition Razavi Solutions Manual

https://testbankfan.com/product/rf-microelectronics-2nd-edition-
razavi-solutions-manual/

Decision Support and Business Intelligence Systems 9th


Edition Turban Test Bank

https://testbankfan.com/product/decision-support-and-business-
intelligence-systems-9th-edition-turban-test-bank/

Principles of Heat Transfer 8th Edition Kreith


Solutions Manual

https://testbankfan.com/product/principles-of-heat-transfer-8th-
edition-kreith-solutions-manual/

Business 12th Edition Pride Solutions Manual

https://testbankfan.com/product/business-12th-edition-pride-
solutions-manual/

Small Business Management Launching and Growing


Entrepreneurial Ventures 17th Edition Longenecker Test
Bank

https://testbankfan.com/product/small-business-management-
launching-and-growing-entrepreneurial-ventures-17th-edition-
longenecker-test-bank/
Preface to Marketing Management 14th Edition Peter
Solutions Manual

https://testbankfan.com/product/preface-to-marketing-
management-14th-edition-peter-solutions-manual/
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions

Chapter 9: High-Level Synchronization and Interprocess


Communication
Exercises

1. Here is one solution. Another one uses the monitor to encapsulate the resources rather
than just the entry and exit.

monitor sharedV {
public enter(int i) {set i busy;};
public exit(int i) {set i idle;};
};

p_0() {
...
enter(2);
access V_2;
exit(2)
...
}

p_1() {
...
enter(0);
access V_0
exit(0)
...
enter(2);
access V_2;
exit(2)
...
enter(0);
enter(2);
access V_0
access V_2;
exit(0)
exit(2)
}

p_2() {
...
enter(0);
access V_0
exit(0)
...
enter(1);
access V_1;
exit(1)
...
enter(0);
enter(1);
access V_0
access V_1;
exit(0)

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
exit(1)
}

p_3() {
...
enter(1);
access V_1;
exit(1)
...
}

2. Here is one solution.

semaphore s0 = 1, s1 = 1, s2 = 1;
...
P_simultaneous(...);
V_simultaneous(...);

p_0() {
...
P_simultaneous(s0, s1);
access V_0 & V_1;
V_simultaneous(s0, s1);
...
}

p_1() {
...
P_simultaneous(s1, s2);
access V_1 & V_2;
V_simultaneous(s0, s1);
...
}

p_2() {
...
P_simultaneous(s0, s2);
access V_0 & V_2;
V_simultaneous(s0, s1);
...
}

3. Here is one solution.

monitor semaphore {
private:
int count = 1; /* set to the initial value of the semaphore
*/
condition hold;
public:
P() {count--; if(count <= 0) hold.wait;};
V() {count++; hold.signal:};
};

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions

4. Condition variables are just signaling semaphores (such as the full/empty semaphores
in the bounded buffer problem). The solution to this problem requires that you know
how mutual exclusion is implemented in the monitor. Then the condition variable
wait code must enqueue the thread and release the mutual exclusion. Similarly, the
signal code obtains mutually exclusive access to the monitor and dequeues a thread.
You will need to provide some guidance as to the amount of detail you want as an
acceptable solution to this problem. Here is some pseudo code (that has only been
debugged “by eye”):

struct monitor_t {
private:
semaphore mutex = 1;
int cv = 0;
<ADT data structures>
...
public:
proc_i(...) {
P(mutex);
<processing for proc_i>
/* CV wait */
cv--;
while(cv < 0) {
enqueue(self, cv_list);
setState(self, blocked);
V(mutex);
yield(); /* Call the scheduler */
P(mutex);
}
/* CV signal */
cv++;
if(cv <= 0) {
pid = dequeue(cv_list);
setState(pid, ready);
V(mutex);
yield(); /* Call the scheduler */
P(mutex);
}
V(mutex);
};
...
};

5. The idea is to translate the solution for #4 into System V semaphores:

struct monitor_t {
private:
union semun {
int val;
struct semid_ds *buf;
ushort * array;
} arg;
arg.val = 1; /* Initial value of semaphore */
int mutex;
struct sembuf opns[1];

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
int cv = 0; /* You could use an event here, but it will be
* tricky releasing the mutex
*/
<ADT data structures>
...
public:
monitor_t() {
mutex = semget(MY_MONITOR, 1, 0666|IPC_CREATE);
if(mutex < 0)
{
fprintf(stderr, "Semaphore not available\n");
exit(0);
}
if(semctl(id, 0, SETVAL, arg) < 0)
{
fprintf( stderr, "Unable to set semaphore value\n");
}
/* Set up the sembuf structure. */
opns[0].sem_num = 0;
opns[0].sem_flg = 0;
};
proc_i(...) {
/* P(mutex) */
opns[0].sem_op = -1;
semop(id, opns, 1);
<processing for proc_i>
/* CV wait */
cv--;
while(cv < 0) {
enqueue(self, cv_list);
setState(self, blocked);
/* V(mutex) */
opns[0].sem_op = 1;
semop(id, opns, 1);
yield(); /* Call the scheduler */
/* P(mutex) */
opns[0].sem_op = -1;
semop(id, opns, 1);
}
/* CV signal */
cv++;
if(cv <= 0) {
pid = dequeue(cv_list);
setState(pid, ready);
/* V(mutex) */
opns[0].sem_op = 1;
semop(id, opns, 1);
yield(); /* Call the scheduler */
/* P(mutex) */
opns[0].sem_op = -1;
semop(id, opns, 1);
}
/* V(mutex) */
opns[0].sem_op = 1;
semop(id, opns, 1);
};
...

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
};

6. Here is the basic idea of a solution:

struct monitor_t {
private:
HANDLE mutex;
Char *mName = “mutexName”;
int cv = 0;
<ADT data structures>
...
public:
monitor_t() {
mutex = CreateMutex(NULL, FALSE, mName);
};
proc_i(...) {
WaitForSingleObject(mutex, INFINITE); /* P(mutex */
<processing for proc_i>
/* CV wait */
cv--;
while(cv < 0) {
enqueue(self, cv_list);
setState(self, blocked);
ReleaseMutex(mutex); /* V(mutex) */
yield(); /* Call the scheduler */
WaitForSingleObject(mutex, INFINITE); /* P(mutex) */
}
/* CV signal */
cv++;
if(cv <= 0) {
pid = dequeue(cv_list);
setState(pid, ready);
ReleaseMutex(mutex); /* V(mutex) */
yield(); /* Call the scheduler */
WaitForSingleObject(mutex, INFINITE); /* P(mutex) */
}
ReleaseMutex(mutex); /* V(mutex) */
};
...
};

7. Here is one solution.

monitor sleepy_barber {
private:
int number_of_customers = 0;
condition_variable haircut, sleepy;

public:
request_haircut {
number_of_customers = number_of_customers + 1;
if (number_of_customers == 1) sleepy.signal;
haircut.wait;

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions

take_customer {
if (number_of_customers == 0) sleepy.wait;
number_of_customers = number_of_customers - 1;
haircut.signal;
}

The barber is a cyclic process of the form:


while (TRUE) {
sleepy_barber.take_customer;
cut_hair
}

Each customer has the form:


...
sleepy_barber.request_haircut
get_haircut;
...

8. An asynchronous send operation can be used in any situation in which the sending
process wishes to transmit information to a sender, but it does not care when the
message is received. In the SOR example, the central process can assign work to an
equation solver using an asynchronous send. (The centralized process will ultimately
have to synchronize the completion of the equation solutions by all the solvers, but
the allocation of work need not have synchronization.)
Suppose two processes, p_0 and p_1, cooperate with one another so that they
generally operate independently and concurrently, but they occasionally share
information by p_0 sending information to p_1; with a synchronous send, p_0 can
procede after its send operation with the assurance that p_1 has received the
information. This communication paradigm is used in remote procedure call
(described in detail in Chapter 17).

9. If a set of processes are working on a common problem, i.e., the work has been
partitioned and delegated to various processes, then the run time will be reduced if all
the processes can execute at the same time. This follows because a fixed amount of
work is divided, then two or more processes perform parts of the work simultaneously
(in a system with multiple processors). Blocking receive operations tend to make a
process wait for one or more other processes to "catch up," reducing the effective
amount of concurrency in the execution. However, as we have seen in various
examples in Chapters 8 and 9, concurrent operation on shared information means that
it is necessary to incorporate a synchronization mechanism to manage sharing -- a
factor that considerably raises the complexity of the software.
10. Condition variables are used to suspend a process while it is logically in a critical
section. In a user thread package, the programmer controls the scheduling of threads
within an address space (process). Therefore, the programmer can determine
situations in which a thread is in a critical section, yet needs another critical section,
and thus can suspend the thread from executing until the needed critical section can

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions

become available. Notice that this is not generally possible at the process level, since
there is not parent to control the schedule and to suspend other processes.
11. The Mach C thread cthread_fork() is similar to UNIX fork() in that it creates a
new thread. It is different in that the thread is given a specific procedure where it will
begin execution (same address space, but a different location from the parent thread).
When the C thread terminates, there is no synchronization with the parent thread.
12. This solution (with minor edits) provided by Don Lindsay, Fall, 1995.

===========================================================================
===========================================================================
/* parent.c
*
* Example program by Don Lindsay
*
*
* This program uses the trapezoidal rule to integrate
* f(x) = 1/(x+1)
* on [0,2]. It does this by forking N processes, each of which
* does n/N trapezoids.
* The parent specifies tasks over N pipes, and recieves answers over one
* shared pipe.
* The parent reports the totalled area, and reports the elapsed integration
* time, ie excluding the setup time. The time is the average of many runs.
* This program must be run with N between 1 and 8, and n=64.
*
* Tested on Linux: portability unknown.
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>>
#include <errno.h>
#include <fcntl.h>
#include <math.h>

#define REPEAT (4000)


#define NUMSTEPS (64)
#define PATHNAME "./child"

#define PRINT if(debug)fprintf


#define PRINT2 if(debug>1)fprintf
extern char **environ;

#ifndef FALSE
#define FALSE 0
#define TRUE 1
#endif
typedef int Boolean;
/*typedef unsigned char u_char;*/

#define PIPE_IN (0)


#define PIPE_OUT (1)

int debug = 0;

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
int forkcount;
int pipes_to_child[8][2];
int pipe_from_child[2];

/****************************************************************
*
*/
void fatal( char *string )
{
fprintf( stderr, "FATAL ERROR: %s\\n", string );
exit(1);
}
/****************************************************************
*
*/
void system_fatal( char *string )
{
fprintf( stderr, "FATAL SYSTEM ERROR: ");
perror( string );
exit(1);
}
/****************************************************************
*
*/
void prompt()
{
fprintf( stderr, "TRY: parent N [-d]\\n" );
exit(1);
}
/****************************************************************
*
* Sets globals forkcount, debug
*/
void parse_my_args( int argc, char **argv )
{
if( argc < 2 || argc > 3 ) prompt();
if( argc == 3 ){
if( strcmp( argv[2], "-d" ) == 0 )
debug = 1;
else if( strcmp( argv[2], "-D" ) == 0 )
debug = 2;
else
prompt();
}
forkcount = atoi( argv[1] );
PRINT( stderr, "forkcount %d\\n", forkcount );
if( forkcount < 1 || forkcount > 8 ) fatal( "arg out of range" );
}
/****************************************************************
*
* Fork that many children.
* Leaves global pipes_to_child and pipe_from_child. These are the
* stdin and stdout of each child.
* Exits on error.
*/
void fork_solvers( int forkcount )
{
int i;
pid_t pid;
char *child_argv[2];
child_argv[0] = PATHNAME;
child_argv[1] = NULL;

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
if( pipe( pipe_from_child )) system_fatal( "Pipe" );
for( i = 0; i < forkcount; i++ ) {
if( pipe( pipes_to_child[i] )) system_fatal( "Pipe" );

PRINT( stderr, "about to fork\\n" );


pid = fork();
if( pid == 0 ) {
/* I am the i'th child. */

if( close(0))
system_fatal("Close1");
if( dup( pipes_to_child[i][PIPE_IN ])==-1)system_fatal("dup1");
if( close(1))
system_fatal("Close2");
if( dup(pipe_from_child[ PIPE_OUT ])==-1)system_fatal("dup2");

/* child's stdin and stdout are now the pipes */

execve( PATHNAME, child_argv, environ );


fprintf( stderr, "exec of \\"%s\\" failed:\\n", PATHNAME );
system_fatal( "Child" );
exit(1);
}
/* I am the parent */
if( pid == -1 ) {
system_fatal( "Fork Parent" );
}
}
}
/***************************************************************
*
* Expects globals pipes_to_child, pipe_from_child.
* Writes step requests to those pipes, and returns the sum of the results.
*/
float farm_out_work( int forkcount )
{
u_char out_buf;
float in_buf;
int in_buf_len = sizeof( float );
float area;
int i, child;

/* Try to get them all working by writing all before any reads */

for( child = 0, i = 1; i <= NUMSTEPS; child++, i++ ) {


if( child >= forkcount ) child = 0; /* wrap around */

out_buf = i;
if( write( pipes_to_child[child][PIPE_OUT], &out_buf,1)!=1)
system_fatal( "write" );
}
for( area = 0.0, i = 1; i <= NUMSTEPS; i++ ) {
if( read( pipe_from_child[PIPE_IN], &in_buf,in_buf_len)
!= in_buf_len )
system_fatal( "read pipe" );
PRINT( stderr, "parent: %d gets area = %g\\n", i, in_buf );
area += in_buf;
}
PRINT( stderr, "parent: %d gets area = %g\\n", i, in_buf );
return area;
}
/****************************************************************
*

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
*
*/
void kill_solvers( int forkcount )
{
int i;
char out_buf;
out_buf = 0;

for( i = 0; i < forkcount; i++ ) {


if( write( pipes_to_child[i][PIPE_OUT], &out_buf,1)!=1)
system_fatal( "kill write" );
}
}
/******************************************************************
*
* Returns system time in milliseconds.
*/
double get_sys_time()
{
struct timeval t; /* int fields tv_sec, tv_usec */
double time;
int result = gettimeofday( &t, 0 );
if( result ) {
fprintf( stderr, "error from gettimeofday\\n" );
perror( "" );
exit(1);
}
PRINT( stderr, "%d %d\\n", t.tv_sec, t.tv_usec );
time = t.tv_sec * 1.e6 + t.tv_usec; /* in microseconds */
return time / 1000;
}
/****************************************************************
*/
main( int argc, char **argv )
{
double start, stop;
int i;
float area;

parse_my_args( argc, argv ); /* get forkcount */


fork_solvers( forkcount );

start = get_sys_time();
/* Must integrate many times to get a measurable amount of time. */
for( i = 0; i < REPEAT; i++ ) {
area = farm_out_work( forkcount );
}
stop = get_sys_time();

fprintf( stdout, "area is %g\\n", area );


fprintf( stdout, "time per integration is %g ms.\\n",
(stop-start)/REPEAT );
kill_solvers( forkcount );
exit(0);
}
===========================================================================
===========================================================================
/* child.c - to be invoked by "parent", forked integrator.
*
* Example program by Don Lindsay
*
*
* This program is used to integrate (via trapezoids) the function

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
*/
#define FUNC(x) (1/(x+1.0))
#define NUMSTEPS (64)
#define INTERVAL_LO (0.0)
#define INTERVAL_HI (2.0)

/* Reads 1-byte integers, one at a time, from stdin.


* A value in the range 1..NUMSTEPS causes a single trapezoid
* to be computed, and its area written (as a binary float) to stdout.
* Zero means quit: all else is a fatal error.
* Each trapezoid represents a 1/NUMSTEPS part of the INTERVAL.
*
* Tested on Linux: portability unknown.
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>

#define PRINT if(debug)fprintf


#define PRINT2 if(debug > 1)fprintf
extern char **environ;

typedef int Boolean;


/*typedef unsigned char u_char;*/

int debug = 0;
int forkcount;
/****************************************************************
*
*/
void fatal( char *string )
{
fprintf( stderr, "FATAL ERROR: %s\\n", string );
exit(1);
}
/****************************************************************
*
*/
void parse_args( int argc, char **argv )
{
if( argc != 1 ) {
fprintf( stderr, "Illegal arglist to child: %d\\n", argc );
exit(1);
}
}
/****************************************************************
*
*/
void system_fatal( char *string )
{
fprintf( stderr, "CHILD FATAL SYSTEM ERROR: ");
perror( string );
exit(1);
}

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
/****************************************************************
*
* Returns the area under f(x1)..f(x2) assuming f is linear between.
* Assumes x2 > x1.
* Expects macro FUNC.
*/
float trapezoid( float x1, float x2 )
{
float f1 = FUNC(x1);
float f2 = FUNC(x2);
return (x2-x1) * (f1+f2)/2.;
}
/****************************************************************
*
* Returns area of indexed trapezoid.
*/
float integrate( int index )
{
float x1, x2, deltax;

deltax = (INTERVAL_HI - INTERVAL_LO)/ NUMSTEPS;


x1 = INTERVAL_LO + index * deltax;
x2 = x1 + deltax;
return trapezoid( x1, x2 );
}
/****************************************************************
*/
main( int argc, char **argv )
{
int area_len = sizeof(float);
float area;
u_char buf;

parse_args( argc, argv );


for(;;) {
if( read( 0, &buf, 1 ) != 1 ) system_fatal( "read" );
PRINT( stderr, "child reads %d from pipe.\\n", buf );
if( buf == 0 ) exit(0);
if( buf > NUMSTEPS ) {
fprintf( stderr, "child: illegal %d read.\\n", buf );
exit(1);
}
area = integrate( buf-1 );
PRINT( stderr, "Child: area %d is %g\\n", buf, area );
if( write( 1, &area, area_len ) != area_len ) system_fatal( "write" );
}
}

13. Here is the quadrature problem using Mach C threads (with politically incorrect name
for the trapezoid solver code).

===========================================================================
===========================================================================
/* Trapezoidal Rule Quadrature using Mach C threads
*
* Use the following command to compile this file
* (assumed to be named trapezoid.c)
*
* trapezoid: trapezoid.o timer.o
* cc -g -o trapezoid trapezoid.o timer.o
*
* trapezoid.o: trapezoid.c

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
* cc -c trapezoid.c
*
*/

#include

/* #define TRUE 1 */
#define bottomRange 0.0
#define topRange 2.0
#define intervals 64
#define maxN 8

#define iLeft(i) 2*i+N


#define iRight(i) 2*i+N+1

/* Local function prototypes */


void solver(int);

/* Shared memory map


*
* Result from Solver 0
* Result from Solver 1
* ...
* Result from Solver N-1
* Left endpoint for Solver 0
* Right endpoint for Solver 0
* Left endpoint for Solver 1
* Right endpoint for Solver 1
* ...
* Left endpoint for Solver N-1
* Right endpoint for Solver N-1
*
* The memory descriptors follow ...
*/
float *shMem; /* Pointer to shared memory as floats */
char *cshMem; /* Pointer to shared memory as chars */

/* Locks for synchronization between solvers and master */


mutex_t resultLock[maxN];
mutex_t segLock[maxN];

extern int errno;


int N;

main (argc, argv)


int argc;
char *argv[];
{
cthread_t t_handle[maxN];
cthread_t cthread_fork();

float getTime();
float currentLeft, currentRight;
float length, result;
float startTime, stopTime;

int i, nAlive, solverNum;

unsigned lengthSM;

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions

/* Get a value of N from the command line */


if(argc == 2)
{
N = atoi(argv[1]);
if (N > maxN)
{
printf("Usage: N is too large\n");
exit(0);
};
}
else
{
printf("Usage: trapezoid N\n");
exit(0);
};

/* Initialize variables for the test */


result = 0.0;
length = (topRange-bottomRange)/(float)intervals;
currentLeft = bottomRange;
currentRight = bottomRange;
cthread_init(); /* Initialize the C threads package */

/* Create the shared memory */


lengthSM = 3*N*sizeof(float); /* See shared mem map above */
cshMem = malloc(lengthSM); /* Make the space be shared */
shMem = (float *) cshMem; /* Access the array as floats */

/* Create the N solvers */


for (i=0; i < N; i++)
{
shMem[iLeft(i)] = 0.0;
shMem[iRight(i)] = 0.0;
/* Setup locks on the buckets */
resultLock[i] = mutex_alloc();
mutex_lock(resultLock[i]);
segLock[i] = mutex_alloc();

/* Create the solver thread */


t_handle[i] = cthread_fork(solver, i);
};

nAlive = N;

/* This loop controls the dispatching of requests and processing of results


*/
startTime = getTime(); /* Starting time */
solverNum = 0;
while (nAlive > 0)
{
/* Wait for a message from a solver */
while (!mutex_try_lock(resultLock[solverNum]))
{
cthread_yield();
solverNum = (solverNum +1) % N;
};

/* Acquired lock */
result = result + shMem[solverNum];

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
/* Dispatch new work to the solver that just finished */
if (currentRight+length <= topRange)
{ /* Assign the next segment to the solver */
shMem[iLeft(solverNum)] = currentLeft;
shMem[iRight(solverNum)] = currentRight;
mutex_unlock(segLock[solverNum]);
currentLeft = currentRight;
currentRight = currentRight + length;
}
else
{ /* Eliminate the solver */
shMem[iLeft(solverNum)] = 1.0;
shMem[iRight(solverNum)] = 0.0;
mutex_unlock(segLock[solverNum]);
cthread_join(t_handle[solverNum]);
nAlive--;
};
};

/* All done -- Report the time & result for this iteration */
stopTime = getTime();
printf("%d processes required %6.2f seconds, result = %f\n",
N, stopTime-startTime, result);

exit(0);
}

/*------------ The Solver Thread Schema --------------- */

void solver(me)
int me;
{
float left, right;
float result;
int i;

/* Ask for initial work by writing a result of zero */


mutex_lock(segLock[me]); /* This should pass immediately */
shMem[me] = 0.0;
mutex_unlock(resultLock[me]);

left = 0.0;
right = 0.0;
while (TRUE)
{
/* Wait for a pair of endpoints */
mutex_lock(segLock[me]);
left = shMem[iLeft(me)];
right = shMem[iRight(me)];

/* Terminate if the left endpoint is greater than the right */


if (left > right) cthread_exit(0);

/* make the call measurable */


for (i=0;i < 1000;i++) cthread_yield();

shMem[me] = ((1.0/(left+1.0))+(1.0/(right+1.0)))/2.0*(right-
left);

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
mutex_unlock(resultLock[me]);
};

Here is the SOR problem using Mach C threads.

#include <stdio.h>
#include <cthreads.h>

#define MAX_N 4

/* Local function prototype */


void solver(int);

/* Shared memory among the threads */


mutex_t lock[MAX_N];
float A[MAX_N][MAX_N], b[MAX_N], x[MAX_N];

int N;

main(argc, argv)
int argc;
char *argv[];
{
FILE *data_fp, *fopen();
int i;
int tmp;
double double_eps;
float error, check();
float epsilon;
float solveX();
char data_filename[128];
char host_filename[128];

cthread_t t_handle[MAX_N];
cthread_t cthread_fork();

/* Get data from file; first, get the command line parameters ... */
if(argc == 3)
{
double_eps = atof(argv[1]);
epsilon = double_eps;
strcpy(data_filename, argv[2]);
}
else
{
printf("Usage: chaosMaster \n");
exit(0);
};

/* ... then read the data file */


printf("Opening %s ...\n", data_filename);
if((data_fp = fopen(data_filename, "r")) == NULL)
{
printf("Open on %s failed, exiting ...\n", data_filename);
exit(1);
};
fscanf(data_fp, "%d", &tmp);
N = tmp;
if(N > MAX_N)
{

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
printf("Degree %d is too large, halting ...\n", N);
exit(1);
};
for (i=0;i < N;i++)
fscanf(data_fp,"%f%f%f", &A[i][0], &A[i][1], &A[i][2]);
fscanf(data_fp,"%f %f %f", &b[0], &b[1], &b[2]);
fscanf(data_fp,"%f %f %f", &x[0], &x[1], &x[2]);
fclose(data_fp);

/* Echo the input */


printf("N = %d\n", N);
for (i=0;i < N;i++)
printf("A[%d][*] = %f %f %f\n", i, A[i][0], A[i][1],
A[i][2]);
printf("b[*] = %f %f %f\n", b[0], b[1], b[2]);
printf("x[*] = %f %f %f\n", x[0], x[1], x[2]);

/* Create the N solvers */


/* This is the code for dynamically defined (cthreads) N */
for (i=0; i < N; i++)
{
/* Initialize lock */
lock[i] = mutex_alloc();
t_handle[i] = cthread_fork(solver, i);
};

/* Solve the system */


error = 1000000.0;
while(error > double_eps)
{
/* Proceed only if all solvers are locked */
for (i=0; i < N; i++)
{
while(mutex_try_lock(lock[i]))
{ /* wasn't locked -- restore it*/
mutex_unlock(lock[i]);
cthread_yield();
};
};
error = check(A, x, b, N);
for (i=0; i < N; i++)
mutex_unlock(lock[i]);
cthread_yield();
};

printf("Solution x[*] = %f %f %f\n", x[0], x[1], x[2]);


printf(" With error factor = %f\n", error);
exit(0);
}

float check(A, x, b, n)
float A[][4], x[], b[];
int n;
{
int i, j;
float sum;
float error;

error = 0.0;
for(i=0; i < n; i++)
{

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
sum = 0.0;
for (j=0; j < n; j++)
sum = sum + A[i][j]*x[j];
error = error + (sum - b[i]);
};
if(error<0.0) error = -error;
return(error);
}

/*--------- The Solver Thread Schema -----------*/


void solver(me)
int me;
{
int j;

cthread_yield();
for(;;)
{
mutex_lock(lock[me]);
x[me] = b[me];
for (j=0;j < N; j++)
if(me!=j) x[me] = x[me] - A[me][j]*x[j];
x[me] = x[me]/A[me][me];
};
}

14. SOR with pipes

#include <stdio.h>
#include <signal.h>

#define MAX_N 4

int N;
double A[MAX_N][MAX_N], b[MAX_N];
int xout[MAX_N][2];
int xin[MAX_N][2];

int main(int argc, char *argv[]) {


double check(double [][MAX_N], double [], double [], int);
void solver(int);

FILE *data_fp, *fopen();


int i, j;
int status;
int solverPID[MAX_N];
double epsilon, newX;
double x[MAX_N];
char data_filename[128];

/*******************************************************/
/* Get the command line parameters ... */
if(argc == 3) {
sscanf(argv[1], "%lf", &epsilon);
strcpy(data_filename, argv[2]);
} else {
printf("Usage: sor \n");
exit(1);

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
};

/* Now read the data from the file */


printf("Epsilon = %lf, opening %s ...\n", epsilon, data_filename);
if((data_fp = fopen(data_filename, "r")) == NULL) {
printf("Open on %s failed, exiting ...\n", data_filename);
exit(1);
};
fscanf(data_fp, "%d", &N);
if(N > MAX_N) {
printf("Degree %d is too large, halting ...\n", N);
exit(1);
};
printf("N = %d\n", N);

/* Read the A matrix */


for (i=0; i < N; i++) {
for (j=0; j < N; j++) {
fscanf(data_fp,"%lf", &A[i][j]);
printf(" A[%d, %d] %lf", i, j, A[i][j]);
};
printf("\n");
};

/* Read the b vector */


for (j=0; j < N; j++) {
fscanf(data_fp,"%lf", &b[j]);
printf(" b[%d] %lf", j, b[j]);
};

/* Read the x vector guess */


printf("\n");
for (j=0; j < N; j++) {
fscanf(data_fp,"%lf", &x[j]);
printf(" x[%d] %lf", j, x[j]);
};

printf("\n");
fclose(data_fp);

/*******************************************************/
/* Create the N solvers */
for (i=0; i < N; i++) {
pipe(xin[i]); /* Pipe for solver[i] to return x[i]
*/
pipe(xout[i]); /* Pipe for solver[i] to get x[j] */
if((solverPID[i] = fork()) == 0) {;
solver(i); /* The i-th child runs this code */
exit(1); /* Never get here -- never returns */
};
};
/* The parent continues ... */

/*******************************************************/
/* Iteratively solve the system */
while(check(A, x, b, N) > epsilon) {
/* Distribute the newest x values*/
for (i=0; i < N; i++) {
for(j=0; j < N; j++)
if(j != i)

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
write(xout[i][1],
&x[j],sizeof(double));
};
/* Read x[i] from xin[i]. Since we cannot procede beyond
* this loop until ALL solvers have returned a value, we can
* use a blocking read here, i.e., we can wait for all in any order.
*/
for (i=0; i < N; i++)
read(xin[i][0], &x[i], sizeof(double));
};

/* Solution converged -- terminate the solvers */


for (i=0; i < N; i++) {
kill(solverPID[i], SIGTERM);
wait(&status);
};

/* Report the results */


printf("\nSolution with error factor = %lf:\n", check(A, x, b, N));
for (i=0; i < N; i++) {
printf(" x[%d] = %lf\n", i, x[i]);
};
printf("\n");
}

double check(double A[][MAX_N], double x[], double b[], int n) {


int i, j;
double sum, error;

error = 0.0;
for(i=0; i < n; i++) {
sum = 0.0;
for (j=0; j < n; j++)
sum = sum + A[i][j]*x[j];
error = error + (sum - b[i]);
};
if(error < 0.0) error = -error;
return(error);
}

/*--------- The Solver Schema -----------*/


void solver(int me) {
int i;
double x[MAX_N];

for(;;) {
/* Get new x values */
for(i=0; i < N; i++)
if(i != me)
read(xout[me][0], &x[i], sizeof(double));
x[me] = b[me];
for (i=0; i < N; i++)
if(i != me) x[me] = x[me] - A[me][i]*x[i];
x[me] = x[me]/A[me][me];
/* Return the new x[me] value */
write(xin[me][1], &x[me], sizeof(double));
};
}

15. This solution is provided by Sam Siewert, Spring, 1996.

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
Makefile:

#CFLAGS = -g -DDEBUG
CFLAGS = -g
CC = cc
SRC =
OBJ = ${SRC:.c=.o}
HDR =
MAINSRC = vt.c

.SUFFIXES: .c.o

vt: ${OBJ} ${MAINSRC} ${HDR}


${CC} ${CFLAGS} vt.c ${OBJ} -o $@

.c.o:
${CC} -c ${CFLAGS} $<

${OBJ}: ${HDR}

clean:
rm vt

Virtual Terminal Manager:

#include <signal.h>
#include <stdio.h>
#include <termio.h>
#include <unistd.h>
#include <fcntl.h>

#define TRUE 1
#define FALSE 0
#define NUMCOL 80
#define NUMLINES 25
#define NUM_VTS 2

struct vt_status_st {
int line;
int bufchars;
int total_lines_out;
int pid;
int running;
int inputchars;
int awaiting_newinput;
};

static struct vt_status_st vt_status[2];


static int active_vt = 0;
static int pipe_to_child_1[2];
static int pipe_to_child_2[2];
static int pipe_from_child_1[2];
static int pipe_from_child_2[2];

void vt_exit_handler()
{
int status;
int pid;

pid = wait(&status);

if(vt_status[0].pid == pid) {

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
fprintf(stderr, "vt0 exited\n");
close(pipe_from_child_1[0]);
close(pipe_to_child_1[1]);
vt_status[0].running = 0;
if(vt_status[1].running)
active_vt = 1;
else
exit(0);
}
else if(vt_status[1].pid == pid) {
fprintf(stderr, "vt1 exited\n");
close(pipe_from_child_2[0]);
close(pipe_to_child_2[1]);
vt_status[1].running = 0;
if(vt_status[0].running)
active_vt = 0;
else
exit(0);
}
else
fprintf(stderr, "somone else exited?\n");

void vt_abort()
{
write(STDERR_FILENO, "killing vts\n", 12);
fflush(stderr);

if(close(pipe_from_child_1[0]) == -1)
perror("close cp1 input");
if(close(pipe_to_child_1[1]) == -1)
perror("close pp1 output");
if(close(pipe_from_child_2[0]) == -1)
perror("close cp2 input");
if(close(pipe_to_child_2[1]) == -1)
perror("close pp2 output");

kill(vt_status[0].pid, SIGKILL);
kill(vt_status[1].pid, SIGKILL);

exit(-1);
}

main(int argc, char **argv)


{
int pid1, pid2, status, nbytes, i, j, val;
char buffer[NUMCOL];
char vt_buffer[NUM_VTS][NUMLINES][NUMCOL];
char vt_input_buffer[NUM_VTS][NUMCOL];
char c;
struct termio tiold, tinew;
int promptsynch, lastline;

/* clear screen to start */


system("clear");

/* terminal settings for character at a time input */


ioctl(STDIN_FILENO, TCGETA, &tiold);
tinew = tiold;
tinew.c_lflag &= ~ICANON;

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
tinew.c_lflag &= ~(ECHOCTL);
tinew.c_cc[VMIN] = 1;
tinew.c_cc[VTIME] = 0;

if(argc < 3 || argc > 4) {


fprintf(stderr, "usage: vt [-promptsynch]\n");
exit(-1);
}
else if(argc == 4)
promptsynch = 1;
else /* argc must equal 3 */
promptsynch = 0;

/* trap child exit signals */


signal(SIGCHLD, vt_exit_handler);

/* deal with vt manager abort */


signal(SIGINT, vt_abort);

if(pipe(pipe_to_child_1) < 0) {
perror("parent pipe 1");
exit(-1);
}

if(pipe(pipe_to_child_2) < 0) {
perror("parent pipe 1");
exit(-1);
}

if(pipe(pipe_from_child_1) < 0) {
perror("child pipe 1");
exit(-1);
}

if(pipe(pipe_from_child_2) < 0) {
perror("child pipe 2");
exit(-1);
}

pid1 = fork();
vt_status[0].pid = pid1;

if (pid1 == 0) {
#ifdef DEBUG
printf("This is child 1\n");
#endif

/* close write end of pipe_to_child_1 for child */


close(pipe_to_child_1[1]);

/* close read end of pipe_from_child_1 for child */


close(pipe_from_child_1[0]);

#ifdef DEBUG
write(pipe_from_child_1[1], "hello", 5);
nbytes = read(pipe_to_child_1[0], buffer, 5);
buffer[nbytes] = '\0';
printf("Child 1 hears parent %s\n", buffer);
#endif

/* so that write to pipe by VT manager sends data to execed stdin */


dup2(pipe_to_child_1[0], STDIN_FILENO);

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
/* so that read from pipe by VT manager gets data from execed stdout */
dup2(pipe_from_child_1[1], STDOUT_FILENO);

signal(SIGINT, SIG_IGN);
execlp(argv[1], argv[1], (char *)0);
}
else {
#ifdef DEBUG
printf("This is the parent\n");
#endif
pid2 = fork();
vt_status[1].pid = pid2;
if (pid2 == 0) {
#ifdef DEBUG
printf("This is child 2\n");
#endif

/* close write end of pipe_to_child_2 for child */


close(pipe_to_child_2[1]);

/* close read end of pipe_from_child_2 for child */


close(pipe_from_child_2[0]);

#ifdef DEBUG
write(pipe_from_child_2[1], "hello", 5);
nbytes = read(pipe_to_child_2[0], buffer, 5);
buffer[nbytes] = '\0';
printf("Child 2 hears parent %s\n", buffer);
#endif

/* so that write to pipe by VT manager sends data to execed stdin */


dup2(pipe_to_child_2[0], STDIN_FILENO);

/* so that read from pipe by VT manager gets data from execed stdout
*/
dup2(pipe_from_child_2[1], STDOUT_FILENO);

signal(SIGINT, SIG_IGN);
execlp(argv[2], argv[2], (char *)0);
}
else {

/* close write end of child_pipes for parent */


close(pipe_from_child_1[1]);
close(pipe_from_child_2[1]);

/* close read end of parent_pipes for parent */


close(pipe_to_child_1[0]);
close(pipe_to_child_2[0]);

#ifdef DEBUG
printf("This is the parent\n");
nbytes = read(pipe_from_child_1[0], buffer, 5);
buffer[nbytes] = '\0';
printf("Parent hears child 1 %s\n", buffer);
nbytes = read(pipe_from_child_2[0], buffer, 5);
buffer[nbytes] = '\0';
printf("Parent hears child 2 %s\n", buffer);
write(pipe_to_child_1[1], "hello", 5);
write(pipe_to_child_2[1], "hello", 5);

#endif

©2004 «GreetingLine»
Gary Nutt, Operating Systems 3/e
Instructor’s Solutions
vt_status[0].line = 0;
vt_status[1].line = 0;
vt_status[0].total_lines_out = 0;
vt_status[1].total_lines_out = 0;
vt_status[0].bufchars = 0;
vt_status[1].bufchars = 0;
vt_status[0].inputchars = 0;
vt_status[1].inputchars = 0;
vt_status[0].running = 1;
vt_status[1].running = 1;
vt_status[0].awaiting_newinput = 1;
vt_status[1].awaiting_newinput = 1;

ioctl(STDIN_FILENO, TCSETA, &tinew);

/* Make sure writes to child blocking */


val = fcntl(pipe_to_child_1[1], F_GETFL, 0);
val &= ~O_NONBLOCK;
fcntl(pipe_to_child_1[1], F_SETFL, val);

val = fcntl(pipe_to_child_2[1], F_GETFL, 0);


val &= ~O_NONBLOCK;
fcntl(pipe_to_child_2[1], F_SETFL, val);

/* Main Loop for VT Manager */

for(;;) {

/* read program output if any */


if(vt_status[0].awaiting_newinput) {
#ifdef DEBUG
printf("reading vt0 output\n");
#endif
vt_status[0].bufchars = 0;
/* initial blocking read for prompt synch. if applicable */
if(promptsynch) {
nbytes = read(pipe_from_child_1[0],

&(vt_buffer[0][vt_status[0].line][vt_status[0].bufchars]),
1);
}

/* set pipe non-blocking in case there is no output */


val = fcntl(pipe_from_child_1[0], F_GETFL, 0);
val |= O_NONBLOCK;
fcntl(pipe_from_child_1[0], F_SETFL, val);

do {
if(nbytes > 0) {
if(vt_buffer[0][vt_status[0].line][vt_status[0].bufchars] == '\n')
{
#ifdef DEBUG
printf("vt0 read: %s", vt_buffer[0][vt_status[0].line]);
#endif
if(active_vt == 0) {
write(STDOUT_FILENO, vt_buffer[0][vt_status[0].line],
vt_status[0].bufchars+1);
}

vt_buffer[0][vt_status[0].line][vt_status[0].bufchars+1] = '\0';
vt_status[0].line = (vt_status[0].line+1) % NUMLINES;
vt_status[0].total_lines_out++;

©2004 «GreetingLine»
Random documents with unrelated
content Scribd suggests to you:
remain freely available for generations to come. In 2001, the Project
Gutenberg Literary Archive Foundation was created to provide a
secure and permanent future for Project Gutenberg™ and future
generations. To learn more about the Project Gutenberg Literary
Archive Foundation and how your efforts and donations can help,
see Sections 3 and 4 and the Foundation information page at
www.gutenberg.org.

Section 3. Information about the Project


Gutenberg Literary Archive Foundation
The Project Gutenberg Literary Archive Foundation is a non-profit
501(c)(3) educational corporation organized under the laws of the
state of Mississippi and granted tax exempt status by the Internal
Revenue Service. The Foundation’s EIN or federal tax identification
number is 64-6221541. Contributions to the Project Gutenberg
Literary Archive Foundation are tax deductible to the full extent
permitted by U.S. federal laws and your state’s laws.

The Foundation’s business office is located at 809 North 1500 West,


Salt Lake City, UT 84116, (801) 596-1887. Email contact links and up
to date contact information can be found at the Foundation’s website
and official page at www.gutenberg.org/contact

Section 4. Information about Donations to


the Project Gutenberg Literary Archive
Foundation
Project Gutenberg™ depends upon and cannot survive without
widespread public support and donations to carry out its mission of
increasing the number of public domain and licensed works that can
be freely distributed in machine-readable form accessible by the
widest array of equipment including outdated equipment. Many
small donations ($1 to $5,000) are particularly important to
maintaining tax exempt status with the IRS.

The Foundation is committed to complying with the laws regulating


charities and charitable donations in all 50 states of the United
States. Compliance requirements are not uniform and it takes a
considerable effort, much paperwork and many fees to meet and
keep up with these requirements. We do not solicit donations in
locations where we have not received written confirmation of
compliance. To SEND DONATIONS or determine the status of
compliance for any particular state visit www.gutenberg.org/donate.

While we cannot and do not solicit contributions from states where


we have not met the solicitation requirements, we know of no
prohibition against accepting unsolicited donations from donors in
such states who approach us with offers to donate.

International donations are gratefully accepted, but we cannot make


any statements concerning tax treatment of donations received from
outside the United States. U.S. laws alone swamp our small staff.

Please check the Project Gutenberg web pages for current donation
methods and addresses. Donations are accepted in a number of
other ways including checks, online payments and credit card
donations. To donate, please visit: www.gutenberg.org/donate.

Section 5. General Information About


Project Gutenberg™ electronic works
Professor Michael S. Hart was the originator of the Project
Gutenberg™ concept of a library of electronic works that could be
freely shared with anyone. For forty years, he produced and
distributed Project Gutenberg™ eBooks with only a loose network of
volunteer support.
Project Gutenberg™ eBooks are often created from several printed
editions, all of which are confirmed as not protected by copyright in
the U.S. unless a copyright notice is included. Thus, we do not
necessarily keep eBooks in compliance with any particular paper
edition.

Most people start at our website which has the main PG search
facility: www.gutenberg.org.

This website includes information about Project Gutenberg™,


including how to make donations to the Project Gutenberg Literary
Archive Foundation, how to help produce our new eBooks, and how
to subscribe to our email newsletter to hear about new eBooks.
back
back

You might also like