Saturday, April 23, 2016

Linux Programming - The Basics of Pipes

Have you ever wondered how pipes work ? When you type ls | grep stuff, or ls | wc -l some sort of magic seems to happen, but how!? I was curious too so I did some digging. The shell provides this functionality with a pipe. A pipe is one of many IPC (Inter process communication) mechanisms available on Linux that enable communication between processes. When you create a pipe, the kernel sets aside a buffer in kernel space. The maximum number of bytes that can be stored is 65,536 as of kernel 2.6.11. The kernel returns 2 file descriptors wrapped in an array. One of these descriptors can be written to and the other read from. When you write to the pipe your data is copied from userspace to kernel space, when a another process reads it back it is transfered once again from kernel space to userspace. Pipes are meant to be used between related processes, and as such it is necessary to have a basic understanding of forking a process on Linux. Check out my blogpost on the subject. Lets have a look at some code.

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

#define BUF_SIZE 10

int main(int argc, char *argv[])
{
	int pfd[2];
	char buf[BUF_SIZE];
	ssize_t numRead;

	if(argc != 2){
		printf("%s string\n", argv[0]);
		exit(EXIT_SUCCESS);
	}
	if(pipe(pfd) == -1){
		printf("Error creating pipe\n");
		exit(EXIT_FAILURE);
	}
	switch(fork()){
		case -1:
			printf("Error forking\n");
			exit(EXIT_FAILURE);
		case 0:
			if(close(pfd[1]) == -1){
				printf("Error closing write end of pipe\n");
				exit(EXIT_FAILURE);
			}
			for(;;){
				numRead = read(pfd[0], buf, BUF_SIZE);
				if(numRead == -1){
					printf("Error reading from pipe\n");
					exit(EXIT_FAILURE);
				}
				if(numRead == 0)
					break;
				if(write(STDOUT_FILENO, buf, numRead) != numRead){
					printf("Failed to write entire buffer\n");
					exit(EXIT_FAILURE);
				}
				
			
			write(STDOUT_FILENO, "\n", 1);
			if(close(pfd[0]) == -1){
				printf("Error closing read end of pipe from child\n");
				exit(EXIT_FAILURE);
			}
			_exit(EXIT_SUCCESS);
		default:
			if(close(pfd[0]) == -1){
				printf("Error closing read end of pipe from parent\n");
				printf("%s\n", strerror(errno));
				exit(EXIT_FAILURE);
			}
			if(write(pfd[1], argv[1], strlen(argv[1])) != strlen(argv[1])){
				printf("Error writing to pipe\n");
				exit(EXIT_FAILURE);
			}
			if(close(pfd[1]) == -1){
				printf("Error closing write end of pipe\n");
				exit(EXIT_FAILURE);
			}
			wait(NULL);
			exit(EXIT_SUCCESS);
	}
}


First we check that the user entered a command line argument, any string will suffice. Next, we create the pipe with pipe() and pass our 2 element array. The kernel will set aside some memory for our pipe and fill the array with 2 file descriptors, one for reading and one for writing. Then we switch on fork, close the write file descriptor, and loop forever reading from the read end of the pipe and printing the data to STDOUT until we receive EOF. In the parent we close the read file descriptor, write the string to the pipe, and close the write descriptor before waiting on the child to exit. Note, its important to close the write descriptor, otherwise the child will never receive EOF and as such we will be stuck waiting for ever. Its also worth noting that a pipe is unidirectional in nature. If you want to setup a bidirectional pipe, you could use two pipes. One for communicating from parent to child, and one for communicating from child to to parent. There are however, other IPC mechanisms that achieve similar such as shared memory. One more important note before we move on, reads on a pipe are destructive, a read "consumes" the data and even though you can have multiple readers, once a read completes the data is not available to other readers. So then, how is it that the shell uses a pipe to facilitate things like ls | grep stuff or ls | wc -l ? Lets have a look at some code.

#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>


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

	if(pipe(pfd) == -1){
		printf("Error creating pipe\n");
		exit(EXIT_FAILURE);
	}

	switch(fork()){
		case -1:
			printf("Error forking\n");
			exit(EXIT_FAILURE);
		case 0:
			if(close(pfd[0]) == -1){
				printf("Error closing read end of pipe\n");
				_exit(EXIT_FAILURE);
			}
			if(dup2(pfd[1], STDOUT_FILENO) == -1){
				printf("Error duplicating write end FD to STDOUT\n");
				_exit(EXIT_FAILURE);
			}
			if(close(pfd[1]) == -1){
				printf("Error closing unused write descriptor\n");
				_exit(EXIT_FAILURE);
			}
			execlp("ls", "ls", (char *) NULL);
			printf("Error execing ls\n");
			_exit(EXIT_FAILURE);
		default:
			break;
		
	}
	switch(fork()){
		case -1:
			printf("Error creating second child\n");
			exit(EXIT_FAILURE);
		case 0:
			if(close(pfd[1]) == -1){
				printf("Error closing write descriptor\n");
				_exit(EXIT_FAILURE);
			}
			if(dup2(pfd[0], STDIN_FILENO) == -1){
				printf("Error duplicating read descriptor\n");
				_exit(EXIT_FAILURE);
			}
			if(close(pfd[0]) == -1 ){
				printf("Error closing uneeded read descriptor\n");
				_exit(EXIT_FAILURE);
			}
			execlp("wc", "wc", "-l", (char *) NULL);
			printf("Error execing wc\n");
			_exit(EXIT_FAILURE);
		default:
			break;
	}

	if(close(pfd[0]) == -1){
		printf("Error closing descriptor\n");
		exit(EXIT_FAILURE);
	}

	if(close(pfd[1]) == -1){
		printf("Error closing descriptor\n");
		exit(EXIT_FAILURE);
	}
	if(wait(NULL) == -1){
		printf("Error waiting on child\n");
		exit(EXIT_FAILURE);
	}
	if(wait(NULL) == -1){
		printf("Error waiting on child\n");
		exit(EXIT_FAILURE);
	}
	exit(EXIT_SUCCESS);
}




It turns out we have the UNIX philosophy of everything is a file to thank for what is one of the most useful bits of functionality in Linux. Piping commands on the shell is simply a matter of redirecting the STDOUT of one process to the STDIN of another. First we create the pipe, and once again our kernel sets aside a buffer and returns 2 file descriptors in our array. In our first fork, we close the read end of the pipe. The real magic is calling dup2() which copies the write end of the file descriptor to the STDOUT_FILENO, when this process writes to standard out it will now be written to the pipe. Then we exec the ls program which inherits our crafty file descriptor setup. In the second fork, we close the write end of the pipe, and call dup2() which copies the the read end of the pipe to the STDIN_FILENO, and exec wc. Now when this program reads from STDIN it will be reading from the pipe.

Hacker challange - Write a program that will take 2 command line arguments. Pipe the STDOUT of the first program to the write end of a pipe, and pipe the STDIN of the second program to the read end of the pipe.

Pro Tip - Pipes only work between related processes, research how to use a FIFO which works in a similar fashion to pipes but uses a file on disk to allow communication between unrelated processes. If you find you never receive EOF, make sure you closed all the file descriptors when you are finished reading and writing.

Thursday, April 21, 2016

Linux Programming - Login Accounting

I've been a techie my entire life. However, at one point I took a bit of a sabbatical. I went on a side quest and enrolled in some business accounting classes. Ultimately, I decided that while accounting is a worth while endeavor I was better off in front of my PC with gcc and friends. It seems even in the computer world I cannot escape accounting, in particular "Login Accounting". When you run the command "who" on the command line, how does the machine "know" who is currently logged in ? Is it mental telepathy ? No, I'm afraid the answer is not so magical, although it is intriquing. There are a number of functions and structures we need to concern ourselves with defined in utmpx.h. Additionally, we also need to be familiar with 2 files, the utmp file located in /var/run/utmp and the wtmp file located in /var/log/wtmp. The utmp file contains entries representing the users currently logged into the system, these entries are removed when the user logs out. The wtmp file contains the same information as utmp, except the entries in this file persist even after the user logs out. These files are not updated automatically by the kernel, instead programmers that write and deploy login programs must be good citizens and update these files. The utmpx API provides all the functionality required for this task. Lets have a look at how to read records from these files.


#define _GNU_SOURCE
#include <time.h>
#include <utmpx.h>
#include <paths.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
	struct utmpx *ut;
	time_t time;

	if(argc > 1)
		if(utmpxname(argv[1]) == -1){
			printf("Error using alternate file\n");
			exit(EXIT_FAILURE);
		}
	setutxent();

	while((ut = getutxent()) != NULL){
		time = (time_t) ut->ut_tv.tv_sec;
		printf("User: %s	Type: %s	Time: %s\n",
				ut->ut_user, ut->ut_type, ctime(&time));
	}
	endutxent();
	exit(EXIT_SUCCESS);
}



First we define a pointer to a utmpx structure which represents any given entry in the u and wtmp files. In our particular example we only read the user, the entry type and the time the entry was created, if your curious check out the man pages on utmpx for the full definition of the utmpx structure. Next, we check if the user entered a command line argument. By default the utmpx functions will open the utmp file, but if the user enters an argument we will instead open the file path given and in this case the only other releveant file path would be /var/log/wtmp. Next we call setutxent() which rewinds the file to beginning. If we haven't read from the file yet its likely already at the beginning but its good practice to be sure. The function getutxent() will return the next record in the file and update the current location. We loop on this call until it returns NULL which indicates either record not found or EOF. In our particular code snippet we expect to receive a NULL value on EOF. Of course, if we don't write to these files from our login programs, there will be nothing to read and as such the next code sample demonstrates how to update these files.

#define _GNU_SOURCE
#include <time.h>
#include <utmpx.h>
#include <paths.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

int main(int argc, char *argv[])
{
	struct utmpx ut;
	char *devName;

	if(argc < 2){
		printf("%s username [sleep-time]\n", argv[0]);
		exit(EXIT_SUCCESS);
	}

	setutxent();

	memset(&ut, 0, sizeof(struct utmpx));
	ut.ut_type = USER_PROCESS;
	strncpy(ut.ut_user, argv[1], sizeof(ut.ut_user));
	if(time((time_t *) &ut.ut_tv.tv_sec) == -1){
		printf("Error setting time\n");
		exit(EXIT_FAILURE);
	}

	ut.ut_pid = getpid();
	devName = ttyname(STDIN_FILENO);
	if(devName == NULL){
		printf("Error getting ttyname\n");
		exit(EXIT_FAILURE);
	}
	strncpy(ut.ut_line, devName + 5, sizeof(ut.ut_line));
	strncpy(ut.ut_id, devName + 8, sizeof(ut.ut_id));


	if(pututxline(&ut) == NULL){
		printf("Error writing to utmp\n");
		printf("%s\n", strerror(errno));
		exit(EXIT_FAILURE);
	}
	updwtmpx(_PATH_WTMP, &ut);

	sleep((argc > 2) ? atoi(argv[2]) : 15);

	
	ut.ut_type = DEAD_PROCESS;
	time((time_t *) &ut.ut_tv.tv_sec);
	memset(&ut.ut_user, 0, sizeof(ut.ut_user));

	setutxent();
	if(pututxline(&ut) == NULL){
		printf("Error updating utmp\n");
		printf("%s\n", strerror(errno));
		exit(EXIT_FAILURE);
	}
	updwtmpx(_PATH_WTMP, &ut);
	exit(EXIT_SUCCESS);
}

Just like before we call setutxent() to move the location back to the beginning of the file. We initialize the ut structure with memset and start coping in the minimum set of values. In this example we set the name of the user that was passed on the command line, in a real world program set this to the username of the logged in user. We set the pid of the calling process with getpid(), we set the line and line id using the value returned by ttyname(STDIN_FILENO). Next we put the entry in utmp with pututxline(&ut), and wtmp with updwtmpx(_PATH_WTMP, &ut). Instead of hard coding the /var/log/wtmp its best practice to use the definition _PATH_WTMP, which is what we have done here. Next, we sleep for either 15 seconds or whatever value the user passed in, this gives you a chance to run who or the first snippet which dumps all the entries in utmp or wtmp. When the program is finished and the user is logged out we need to do a little house keeping. First we update the ut_type to DEAD_PROCESS to indicate the user has logged out, we update the time, and we zero out the username. Next, we call setuxent() to move the current location back the beginning and call pututxline(&ut) which will update our initial entry. Finally we call updwtmpx(_PATH_WTMP, &ut) to create a logout entry in the persistent wtmp file.

Hacker Challenge - Write a program to search for only USER_PROCESS entries in utmp and wtmp.

Hacker Challenge - Technically we should also be updating the lastlog file to keep track of the last login for each use. Research how to update the lastlog file.

Pro Tip - Have a look at the getutxid() and getutxline() functions for performing various searches on utmp and wtmp. The lastlog file contains entries that are represented by the structure lastlog in lastlog.h. The lastlog file can be opened from _PATH_LASTLOG. Addtionally, if you haven't figured it out by now you need privileges to update lastlog, utmp and wtmp.

Happy Hacking!

Tuesday, April 19, 2016

Standing Desk - A Nerds Hunt For Comfort

These past 5, possibly six months, I've been using a standing desk set-up. Previously I sat at my desk like most people. I went from chair to chair, adjusting the height and the tilt, and at one point I even went so far as to set-up my machine in the living room in front of the couch. I was at a loss, my entire life was spent in front of the machine and if I have anything to say about it I'll spend the remainder in front of my machine. However, I had found myself in a situation where I could not sit at my computer for long periods of time without a lot of discomfort and in fact it began to act as a deterrent. I had heard about standing desks before, but I never really gave it much thought until my discomfort problems peaked.

The initial incarnation of my standing desk was a monitor that sat on top of a TV dinner tray, that sat on top of my desk. I used books and boxes stacked up in front for the keyboard and mouse. In this particular picture I was binging on Sushi while setting up my new PowerEdge 2950 III. Over the past 6 months I discovered a few things. Initially I had even more pain in my back, but after about a week it subsided and I found my back much better. I did however develop some pain in my feet and knees, this pain has subsided overtime and is helped by wearing sneakers and taking breaks during the day. To be honest the threshold is about 3-4 hours, I can and do push longer but sometimes that just results in having to take a day or two rest. One of the benefits I did not expect was increased concentration, productivity and energy levels. After sitting at my machine for hours I often felt lethargic and found myself clicking around the internet and not being very productive. As a standing desk user, I find I'm much more energetic, I get straight to work and concentrate better. Possibly because I know, I can have "some" productive time with a standing desk before I get too tired to stand there, and I want to make use of it.

The second incarnation of my standing desk is still hack, but its much more tidy. My dad has been into building wooden furniture lately and he offered to build me this little table, which can be re-purposed as a foot rest or shoe rack when I do invest in a proper standing desk. After six months I realized that at least for me, standing for the whole 8 hours in a day was not obtainable. Fours hours seems to be the sweet spot. As such, my next investment will be to invest in a tall stool or back rest of some kind so I can take some of the weight off my feet and knees while still working. For the moment I try to be as productive as possible for 3-4 hours and take frequent breaks. It seems to work well, I just spend more time laying down reading, which rests my entire body and I feel refreshed for another session at the machine.

The main points to take away from my experience are

  • Don't try to push for 8 hours a day if its causing too much pain
  • Initially you may have increased discomfort, that subsides soon after
  • Some kind of foot wear is essential, I use sneakers.
  • Its important to take frequent breaks, spend that time reading, or figuring things out
  • If you need to work longer than your legs will allow, invest in a stool or tall chair, this way you can stick to standing and rest a bit when you need.
  • Standing desks are not for everyone, some people are more comfortable and productive sitting and that's perfectly fine!

Happy Hacking!


Thursday, April 14, 2016

Linux Programming - daemon basics

I've always felt that daemons possessed a bit of a mystical property. Maybe its because their name is so similar to the word "Demon", or the infatuation with the fact that a daemon is a slave, running 24/7 doing some useful work for my benefit. I was curious enough, so I did a bit of digging around. Like most magic, once the curtain is pulled back and the trick revealed there is nothing magical about it. We are left with something much more valuable, the truth and if we're lucky some useful knowledge we can make use of.

A daemon is nothing more than a long running process. There is no specific system call or library function to establish a daemon on a system. Instead, a daemon is a program written to behave in a certain way, and most daemons adhere to some norms. The following code sample demonstrates this. If you are unfamiliar with the basics of forking a process, checkout my blog post on the subject.

#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

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

	switch(fork()){
		case -1:
			exit(EXIT_FAILURE);
		case 0:
			break;
		default:
			_exit(EXIT_SUCCESS);
	}

	if(setsid() == -1){
		printf("Error becoming session leader\n");
		_exit(EXIT_FAILURE);
	}

	switch(fork()){
		case -1:
			exit(EXIT_FAILURE);
		case 0:
			break;
		default:
			_exit(EXIT_SUCCESS);
	}

	umask(0);
	chdir("/");
	maxfd = sysconf(_SC_OPEN_MAX);
	for(fd = 0; fd < maxfd; fd++)
		close(fd);

	close(STDIN_FILENO);
	fd = open("/dev/null", O_RDRW);
	if(fd != STDIN_FILENO)
		_exit(EXIT_FAILURE);

	if(dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO)
		_exit(EXIT_FAILURE);

	if(dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO)
		_exit(EXIT_FAILURE);

	for(;;){
		//This daemon will run forever. use ps aux | grep ./[name of program] to
		//find it and kill it. If you don't care to observe its
		//properties while its running remove the endless for loop.
	}
}



The first order of business is forking the process and exiting from the parent. When the child is orphaned it is adopted by the init process. When the parent exits, the terminal notices and returns a prompt to the user, leaving the child in the background. Next we call setsid(), this call creates a new session which frees the process from any association with a terminal. To be sure that the daemon can never reacquire a controlling terminal, we fork a second time. To really understand why this process works, one needs to study the conventions of process groups and sessions. For the prupose of this example it will suffice to say that only the session leader can acquire a controlling terminal, the second fork insures that daemon is not the session leader. Next we clear the umask for the process, the umask is used by sys calls such as open(), and mkdir(). Clearing the mask insures that files are created with the intended permissions. Daemons usually change their root directory, although not required there are a few good reasons to perform a chdir(). If the root directory is not / you will be prevented from un-mounting the file-system the daemon is on. Additionally, It may be nice to restrict the working directory of the daemon, for example ftp servers change the root directory for the logged in user to the users FTP dir. This prevents them from crawling directories outside the intended location. Finally, we close all the file descriptors the child may have inherited from its parent, since the daemon has no controlling terminal it makes no sense to leave standard I/O descriptors open. We redirect standard outputs to /dev/null. If some library function tries to write to the standard output file descriptors it won't error out and all the output just gets discarded in /dev/null. It may also be worth noting why we assume the file descriptor we get back from a call to open is indeed the standard input file descriptor 0. The kernel distributes file descriptor numbers per process starting with the lowest number. Since we closed all the file descriptors before calling open, we should get a file descriptor value of 0.

A common pattern for daemons is to load a configuration file when they are started, and to reload changes while still running. To implement the reload functionality we can setup a signal handler for the SIGHUP signal. Our daemon does not have a terminal associated with it so the kernel will never send a legit SIGHUP signal, making this a good signal to use. If you are unfamiliar with the basics of signal handling on Linux, check out my blog post on the subject. There is a second signal we need to concern ourselves with, and that is SIGTERM. When the system shuts down, init which is parent process to our daemon will send SIGTERM, followed by SIGKILL 5 seconds later. It's important you perform cleanup work quickly, as you likely won't have the full 5 seconds to yourself, other daemons will also be running cleanup routines.

Hacker Challenge - Create a daemon that reports errors to the end user.

Hacker Challenge - Create a program that loads a config file when it loads, and reloads the configuration file when it receives the SIGHUP signal.

Pro Tip - While we could write to a log file of some kind to report errors, a more elegant solution is to use the syslog facility. Check out the manpages for more detailed information.

Sunday, April 10, 2016

Linux Programming - threading basics

It's no secret that the Ghz wars are over. No longer are we bombarded by endless processor releases with ever increasing clock speeds. For some time now in order to pack more performance into a chip companies are putting as high as 12 cores in one chip. Fantastic, the chip should give us a 12X performance boost over a single core chip with the same clock speed, right ? Wrong, software has to be written to take advantage of multi-core technology and this is where pthreads play a role. There are a few functions we need to concern ourselves with all defined in pthread.h. First pthread_create(), pthread_create() takes as a minimum set of arguments, a pointer to a pthread_t type, and a pointer to a user defined function. Second pthread_join(), pthread_join() waits for a specified thread to terminate, similar to calling waitpid() on a forked process.

One of the benefits of using threads over a forked process is shared memory between all the threads in the group. As convieniant as this is, it does come at a slight cost. Consider the scenario where two threads access the same variable at the same time. A simple increment example should suffice to shed light on the problem.

static int global = 0;

static void *threadfunction(void arg)
{
        int local, j;

        for(j = 0; j <= 10; j++){
               local = global;
               local++;
               global = local;
        }
        return NULL;
}



Lets assume the above function is running in 2 threads. Since each thread should increment global by 10, the final result should be 20, right ? Well, maybe. If the kernel decides thread one has had its share of the processor it will schedule another process, possibly thread 2 to run. If this happens before the loop completes thread 2 could begin incrementing global before thread 1 has had a chance to save the local variable back. Indeed, a bright student may point out that we have 3 statements here where we only need 1. Why not increment global directly with global++ ? Well, you can. However, behind the scenes the machine is still doing something akin to storing, incrementing, and assinging the value back to global. The solution to this problem is using a lock, in particular a mutex. Before accessing or modifying a global variable in a thread we should acquire a lock, this insures no other thread can access the variable until we are finished. Take note, there is nothing preventing a thread from accessing a variable without acquiring a lock, its up to the programmer to insure that all threads are good citizens and wait to acquire the lock before accessing a global variable. The use of a mutex requires that we initialize the mutex, and then call pthread_mutex_lock before accessing a global variable. pthread_mutex_lock() will block and wait for the lock to become available if another thread currently holds the lock. We release the lock with pthread_mutex_unluck(). The following code sample demonstrates the use of a mutex.

static int global = 0;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

static void *threadfunction(void arg)
{
        int local, j;
        int s;

        for(j = 0; j<= 10; j++){

               s = pthread_mutex_lock(&lock);
               if(s != 0){
                      printf("Error getting the lock\n");
                      exit(EXIT_FAILURE);
               }

                local = global;
                local++;
                global = local;

                s = pthread_mutex_unlock(&lock);
                if(s !=0 ){
                       printf("Error releasing lock\n");
                       exit(EXIT_FAILURE);
                }
        }
        return NULL;
}



As you can see, each thread will now acquire the lock in each iteration of the loop and only release it after the increment operation completes. The following code sample demonstrates the above concepts in their entirety.

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

static int global = 0;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

static void *threadfunction(void *arg)
{
        int local, j, r;
        for(j = 0; j <=10; j++){
               r = pthread_mutex_lock(&lock);
               if( r !=0 ){
                      printf("Error getting lock\n");
                      exit(EXIT_FAILURE);
               }
  
               local = global;
               local++;
               global = local;

               r = pthread_mutex_unlock(&lock);
               if(r != 0){
                     printf("Error releasing lock\n");
                     exit(EXIT_FAILURE);
               }

        }
        return NULL;
}

int main(int argc, char *argv[])
{
        pthread_t thread1, thread2;
        int r;

        r = pthread_create(&thread1, NULL, threadfunction, NULL);
        if(r != 0){
               printf("Error creating thread\n");
               exit(EXIT_FAILURE);
        }
 
        r = pthread_create(&thread2, NULL, threadfunction, NULL);
        if(r != 0){
               printf("Error creating thread\n");
               exit(EXIT_FAILURE);
        }

        r = pthread_join(thread1, NULL);
        if(r != 0){
               printf("Error joining with thread\n");
               exit(EXIT_FAILURE);
        }
 
        r = pthread_join(thread2, NULL);
        if(r != 0){
               printf("Error joining with thread\n");
               exit(EXIT_FAILURE);
        }
        printf("global= %d\n", global);
        exit(EXIT_SUCCESS);

}



In our main function we spin up our threads with pthread_create(). The first NULL value is an attribute parameter, and the second NULL value is a void pointer where we can pass a parameter that will be passed to our thread function. Recall that the definition for the thread function is threadfunction(void *).

Hacker Challenge - Wouldn't it be nice if we could let our threads know when some action has occurred, such as a global variable has been updated and needs work done ? I agree, it would. Write a program to send a signal to our threads notifying that some condition has been met.

Pro Tip - Don't use "traditional" signals. The pthreads API provides a condition variable for this purpose. Have a look at the man pages for pthread_cond_signal.

Pro Tip - In order to compile programs that use the pthread API, you will need to compile with the option -pthread.

Wednesday, April 6, 2016

Linux programming - reaping zombies

Today I continued my study of process creation on Linux with a quest that included fighting off zombies with wait() magic, and signal handling kung fu. If you are not familiar with the basics of forking, check out my blog post here where I cover the basics of forking processes on Linux. When a child exits on Linux if the parent has not performed a wait on it, the process sticks around as a zombie. The Linux kernel frees all the resources when a process is zombied. However, it still occupies a spot in the kernels process recording table and if this fills up we won't be able to create any new processes in the future. As I understand it, this is mostly a problem for long running processes. When the parent of a process dies, the init process adopts it and performs a wait which clears it from the kernel process recording table. If however, you have a long running parent process, it's important to cleanup zombies by reaping them with wait() to prevent clogging up the process table.

If the purpose of your parent process is to spin up some initial children and then wait for that work to complete, reaping all your zombies is trivial. You simply loop forever and run wait() until all processes have finished. The following snippet demonstrates this technique


for(;;){
       childPid = wait(NULL);
             if(childPid == -1)
       if(errno == ECHILD){
              printf("All chidren are dead\n");
              exit(EXIT_SUCCESS);
       } else {
               printf("Error waiting for child\n");
               exit(EXIT_FAILURE);
       }
}


The snippet is meant to be run from the parent process after you have started up all children. We simply loop forever, waiting for a child to exit. If wait returns -1 we check if the error is ECHILD. If it is, then this means there are no more children left. While this technique would work for some programs, most programs will not want the parent process to block forever waiting for children to die. A more elegant solution involves the use of signal handlers. If you are not familiar with the basics of signal handlers, check out my blog post here covering the basics.

As you may already be aware, the programmer has no control over or any way to predict when signals will arrive. As a result, if we are going to use signal handlers to reap zombies we must block SIGCHLD before we start creating children and only unblock it when we are ready for our program to handle zombies. The following code sample demonstrates this technique in its entirety.In this example I used printf() inside the handler function. While this is probably OK for example code as a way of observing that a handler was triggered it is not appropriate in real world programs. You need to use async safe functions only, in signal handlers. Usually the manual page for functions that are not async safe are explicitly marked in some way, so watch out for this.

#include <signal.h>
#include <sys/wait.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#inlcude <errno.h>
#include <stdio.h>

static volatile int children = 0;

static void handler(int sig)
{
        int status, olderrno;
        pid_t childpid;
 
        olderrno = errno

        printf("SIGCHILD Caught\n"); //unsafe
        while((childpid = waitpid(-1, &status, WNOHANG)) > 0){
                printf("Reaped Child %ld", (long) getpid()); //unsafe
                children--;
        }

        if(childpid == -1 && errno != ECHILD){
               printf("Error waiting for child\n"); //unsafe
        }
 
        errno = olderrno;
        sleep(5);
        printf("Handler returning now\n"); //unsafe
}

int main(int argc, char *argv[])
{
        struct sigaction sa;
        sigset_t blockMask, emptyMask;
 
        setbuf(stdout, NULL);
        children = 10;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = 0;
        sa.sa_handler = handler;

        if(sigaction(SIGCHILD, &sa, NULL) == -1){
               printf("Error registering handler\n");
               exit(EXIT_FAILURE);
        }

        sigemptyset(&blockMask);
        sigaddset(&blockMask, SIGCHLD);
        if(sigprocmask(SIG_SETMASK, &blockMask, NULL) == -1){
               printf("Error blocking SIGCHLD\n");
               exit(EXIT_FAILURE);
        }

        for(int i = 10; i <= 10; i++){
                switch(fork()){
                        case -1:
                                printf("Error forking\n");
                                exit(EXIT_SUCCESS);
                        case 0:
                               sleep(3);
                               printf("Child %d (PID=%ld) exiting\n", i, (long)
                               getpid());
                               _exit(EXIT_SUCCESS);
                        default:
                                break;
                }
        }
        sigemptyset(&emptyMask);
        while(children > 0){
                if(sigsuspend(&emptyMask) == -1 && errno != EINTR){
                       printf("Error suspending\n");
                       exit(EXIT_FAILURE);
                }
        }
        printf("All children terminated, we now get some sleep\n");
        exit(EXIT_SUCCESS);


}



The first task here is to create the handler that will be called when the parent receives a SIGCHLD signal. In our handler, first we save the value of errno and restore it before returning from our handler. If we don't do this errno may contain a value that is not expected outside the handler. Second, we loop inside the handler to reap all children that are currently zombied. I specify the WNOHANG option here so the function call will return immediatly if no child has exited, or we have finished reaping all zombied processes at the time the handler was triggered. At the end we sleep for 5 seconds so we have time to observe whats happening on the console. In our main function the first order of business is blocking SIGCHLD until we are ready to listen for it, and registering our handler. After which I loop and spawn 10 children. Take note that I *know* how many children I'm spawning, in a real world program this is probably not defined at runtime so make sure to keep track of how many children have been spawned so we can be sure to reap all zombies. Then at a time of our choosing, our program can call sigsuspend() with an empty signal mask, in this case we loop and call sigsuspend() until there are no children left and exit. In your program you get to choose when its a good time to listen for SIGCHLD signals and reap zombies. If you still want to block other singles and listen for SIGHLD alone, use sigfillset() to create a full mask of signals and then remove SIGCHLD with sigdelset().

Hacker Challange - Create a program to spawn a number of children and prints the PID of each child to the screen. Have the parent process exit without calling wait(), then check the parent ID of those children. What is the parent ID ?

Pro Tip - Don't let zombies take over your machine, be a good lad and reap them.

Monday, April 4, 2016

Linux Programming - The Basics of Forking

Recently I've been intrigued by process creation on Linux. I love that god mode feeling of forking child processes, waiting for signals from them, and exec'ing other binaries from code. The basics of forking a process on Linux are fairly straight forward and there are only 2 specific calls we need to concern ourselves with. The first is fork(), this system call creates a child process, which continues executing code after the return from fork(). The second is wait(). Wait() is meant to be run from the parent process and does exactly what one would expect. It blocks, and waits for state changes in the child process such as the child exited, the child was stopped by a signal, or the child was resumed by a signal.

There are a few additional things to be aware of when forking processes. You are probably wondering what exactly happens after a call to fork ? Frankly I was a little bit confused about the state of each process and how execution continued after a successful fork, so I dug in and did little hacking. I discovered that as of Linux 2.6.32 the parent process resumes execution before the child. However, not all UNIX implementations behave this way. If you want to write code that is portable you should not rely on the parent running first. If you would like to change this behavior you can place a non-zero value in /proc/sys/kernel/sched_child_runs_first which causes the child to always run first after a successful fork. Second, the child shares all file descriptors that are opened in the parent. Third, when a process is forked the child gets an exact copy of the parents memory. When the child process first spins up it can access any values that the parent had stored, after which the child maintains its own memory separate from the parent. As you might expect the child gets its own PID which is returned to the parent after a succesful fork(). Lets take a look at a code sample to drive these points home.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

static int data = 1;
int main(int argc, char *argv[])
{

       pid_t child;

       switch(child = fork()){
              case -1:
                      printf("Error Forking\n");
                      exit(EXIT_FAILURE);
              case 0:
                     data += 1;
                     break;

              case default:
                           break;
       }
   
        printf("PID=%ld %s data=%d\n", (long) getpid(),
              (child == 0) ? "(child)":"(parent)", data);
        exit(EXIT_SUCCESS)
}


While this is a fairly simple code sample it demonstrates the basics of forking a process and drives a few points home. First, if you run this program you will see that the PID that identifies as the parent runs first and the value of its data variable is 1, the PID that identifies as the child runs second and the value of its data variable is 2. This proves that while the child did get a copy of the parents memory, it now maintains its own memory space. But wait, how does the child know that it should start executing at case 0: and the parent know it should start executing at default: after the successful fork() ? This puzzled me as well, but its actually quite simply. If a fork is not successful it returns -1 to the parent and no child ever exists. If however, the fork is a success fork returns 0 to the child and the PID of the child to the parent. The parent process will switch on default, and the child switches on 0. Lets have a look at a sample that demonstrates shared file descriptors between parent and child.

#include <sys/stat.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
        int fd, flags;
        char tempfile[] = "/tmp/textXXXXX";
 
        setbuf(stdout, NULL);

        fd=mkstemp(tempfile);
        if(fd == -1){
               printf("Error opening temp file\n");
               return -1;
         }

        printf("offset of file in parent before fork(): %lld\n",
                            (long long) lseek(fd, 0, SEEK_CUR));

        switch(fork()){
               case -1:
                       printf("Error forking\n");
                       exit(EXIT_FAILURE);

               case 0:
                      if(lseek(fd, 1000, SEEK_SET) == -1){
                             printf("Error seeking\n");
                             _exit(EXIT_FAILURE);
                      }
                      _exit(EXIT_SUCCESS);
               default:
                       if(wait(NULL) == -1){
                              printf("Error waiting for child to exit\n");
                              exit(EXIT_FAILURE);
                        }
                        printf("Child has exited\n");
                        printf("Parent file offset after fork: %lld\n",
                                   (long long) lseek(fd, 0, SEEK_CUR));
                        exit(EXIT_SUCCESS);
        }
}


This code sample opens a file descriptor, sets a seek value in the child, and then prints the seek value once again from the parent after waiting for the child to exit. As you can see, the file descriptor created in the parent is indeed shared with the child. One can imagine a couple reasons for this behaviour. One, it prevents clogging up the system requiring each child to open unique file discriptors. Second, its a nice convenience to the programmer providing he or she uses it correctly. If you do decide to make use of shared file descriptors be sure to use locks, otherwise things are going to get messy *really* fast.

Hacker Challenge - Change the value of /proc/sys/kernel/sched_child_runs_first to a non-zero value and re-run the first sample program. What is the result ?

Hacker Challenge - Write a program where the child uses a signal to let the parent know it has finished doing some useful work.

Pro Tip - check out the man pages for sigaction, to register your handler. Use kill() to send the signal SIGUSR1. For a basic introduction to sigaction check out my blog post on sigaction.
Privacy Policy