Threads and Locking Ioctl operations. Threads Lightweight processes What’s wrong with processes?...

26
Threads and Locking Ioctl operations

Transcript of Threads and Locking Ioctl operations. Threads Lightweight processes What’s wrong with processes?...

Threads and LockingIoctl operations

Threads

• Lightweight processes

• What’s wrong with processes?– fork() is expensive – 10 to 100 times slower– Inter process communication

• For returning information from child to parent

Threads…• Shared components

– Global memory– Instructions– Most data– Open descriptors (files, sockets etc)– Signal handlers

• Not shared…– Thread ID– Registers, Program counter, stack pointer– Stack– Errno– Signal mask– Priority

Creation

• Thread equivalent of fork()

• int pthread_create(pthread_t * thread,

pthread_attr_t * attr,

void * (*start_routine)(void *),

void * arg

);

• Returns 0 is OK, and non-zero (> 0) if error.

Termination

• Return from initial fuction.• void pthread_exit(void * status)• exit() called by any thread• main() returns

Waiting for child thread to exit

• int pthread_join(pthread_t tid, void **status)

• Equivalent of waitpid()

Detaching a thread

• The detached thread can act as daemon thread

• The parent thread doesn’t need to wait

• int pthread_detach(pthread_t tid)

• Detaching self :

pthread_detach(pthread_self())

Echo client-server

Server

S1 S2

ReadThread

WriteThread

ReadThread

WriteThread

listenfd

Read Write WriteReadClient1 Client2

Thread-based Echo Server

main()

{int listenfd, connfd;

int len;

/* Start the usual way */

listenfd = Socket(…);

Bind(listenfd, …);

Listen(listenfd, …)

for ( ; ; ) {len = addrlen;

connfd = Accept(listenfd, …);

/* Create a thread in service_func routine */

Pthread_create(NULL, NULL, service_func, (void *) connfd);

}

}

void * service_func(void *arg){

int local_connfd;

/* release parent from waiting */Pthread_detach(pthread_self());

/* extract connfd from argument */local_connfd = (int) arg;

/* receive and echo client’s message */str_echo(local_connfd);

/* Terminate the connection */Close(local_connfd);

return(NULL);

}

Thread-based Echo Client

int sockfd;FILE *fp;

main(){

pthread_t tid;fp = fopen(…);

/* Start the usual way */sockfd = Socket(…);…Connect(…);

/* Create a thread to send data */Pthread_create(&tid, NULL, write_func, NULL);

/* read data from sockfd */read_func();

/* wait for child thread */Pthread_join(tid, NULL);

}

void * write_func(void *arg){

char sendline[MAXLINE];

while( more data in fp)Read from fp into sendline[];write sendline[] into sockfd;

Shutdown(sockfd, SHUT_WR);return(NULL);

}

void read_func(){

char recvline[MAXLINE];

while ( more data from sockfd) read from sockfd into recvline[];write from recvline[] to stdout;

}

Mutex – for mutual exclusion

int counter = 0;

void *thread_func(void *arg){int val;

/* unprotected code – why? */val = counter;counter = val + 1;

return NULL;}

Mutex…int counter = 0;ptread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *thread_func(void *arg){int val;

/* protected by mutex */Pthread_mutex_lock( &mutex );val = counter;counter = val + 1;Pthread_mutex_unlock( &mutex );

return NULL;}

Condition Variable – for signaling

• Think of Producer – consumer problem

• Producers and consumers run in separate threads.

• Producer produces data and consumer consumes data.

• Consumer has to inform producer when data is available

Without condition variables

/* Globals */

int data_avail = 0;

int pthread_mutex_t data_mutex =PTHREAD_MUTEX_INITIALIZER;

void *producer(void *)

{

Pthread_mutex_lock(&data_mutex);

Produce data

Insert data into queue;

data_avail++;

Pthread_mutex_unlock(&data_mutex);

consume_data();

}

void *consumer(void *)

{

Pthread_mutex_lock(&data_mutex);

while( !data_avail )

/* do nothing – keep looping!!*/;

Extract data from queue;

if (queue is empty) data_avail = 0;

Pthread_mutex_unlock(&data_mutex);

consume_data();

}

With condition variables

int data_avail = 0;int pthread_mutex_t data_mutex =PTHREAD_MUTEX_INITIALIZER;int pthread_cont_t data_cond = PTHREAD_COND_INITIALIZER;

void *producer(void *) {

Pthread_mutex_lock(&data_mutex);

Produce data

Insert data into queue;data_avail++;

Pthread_cond_signal(&data_cond);

Pthread_mutex_unlock(&data_mutex);

consume_data();}

void *consumer(void *) {Pthread_mutex_lock(&data_mutex);

while( !data_avail ) {/* sleep on condition variable*/Pthread_cond_wait(&data_cond,

&data_mutex);}

/*woken up */Extract data from queue;if (queue is empty) data_avail = 0;

Pthread_mutex_unlock(&data_mutex);

consume_data();}

ioctl()

ioctl()

• Handles miscellaneous properties of a file/device referenced by a descriptor.– In our case, network interfaces.

• int ioctl(int fd, int request, void * arg)

– Socket operations– File operations– Interface configuration– ARP cache– Routing table

• SIOSPGRP/SIOGPGRP– set/get process/group ID of a socket

• FIONREAD– Return number of bytes in socket buffer

• SIOCGIFCONF– Get list of all interfaces

• SIOCGIFBRDADDR/ SIOCSIFBRDADDR– Get/set broadcast address

• SIOCGARP/SIOCSARP/SIOCDARP– Get/modify/delete ARP cache entry.

• SIOCADDRT/SIOCDELRT– Add/delete routes