Cogs and Levers A blog full of technical stuff

Unix IPC: Forking and Waiting

In order to create processes within the Unix environment, you must fork. Forking a process establishes the parent / child relationship which is where the waiting comes into it. All good parents wait for their children to die before terminating.

It’s just good manners, you know?

So, the snippet for this will be a fork and wait set:

/* fork execution here */
pid_t pid = fork();

int child_exit_code;

if (pid < 0) {
 /* -1 indicates that fork failed */
 exit(1);
} else if (pid == 0) {
 /* 0 indicates that this is the child process */
 exit(0);
} else {
 /* the pid being returned indicates it's the parent */
 /* wait for the child to finish and
    capture its exit code */
 wait(&child_exit_code);
}

Further reading

Calling Assembly from C (32 bit)

One of the biggest advantages of being able to write assembly code is to optimise any bits of your application that you want. That way you can maintain your code base in a half-sane language (like C) and roll your sleeves up to speed up the smaller parts that you want.

This blog post will show you how to call a routine that you’ve defined in assembly language from your C code. The example that I’ll show has been done in a Linux environment using NASM as the assembler and GCC for the C compiler.

First of all, let’s write our C program. This will simply add two integers and output the results using printf.

#include <stdio.h>

/** Forward declaration for our add function */
int add(int, int);

int main() {

   /* add some numbers */
   int x = add(5, 4);

   /* print the result out */
   printf("5+4=%d\n", x);

   return 0;
}

There isn’t anything of great interest in here. We have a forward declaration for our add function. That’s about it. Now we have to supply an implementation for our add routine. For this we’ll be using assembly language.

global add

section .text

add:
   mov   eax, [esp+4]    ; get the 1st param
   mov   ecx, [esp+8]    ; get the 2nd param
   add   eax, ecx        ; add them together
                         ; leaving the return value in eax

   ret

This is all pretty straight forward. We define a symbol “add” as global. In the code (or .text) section, we supply an implementation for it. The trickiest part here is being able to retrieve parameters that are passed in from the C level. You can see that we’re addressing stack pointer to do so.

Add takes two parameters. In this scenario (c-calling convention) the parameters to the function are pushed onto the stack in reverse order. So, the second parameter goes onto the stack first and then the first. Once all of the pushing has complete, the first parameter is at [esp+4] and the second is at [esp+8]. Remember - an integer (on this architecture) has 4 bytes (32 bits).

Return values are always left in eax. You’ll see that after the arithmetic completes, it’ll be eax that holds the answer. It’s what will be given back to the caller.

Finally, all we need to do is compile these files and link together their object files. We do this from the Linux console with the following commands.

gcc -m32 -c -g add.c -o add.o
nasm -felf32 maths.asm -o maths.o
gcc -m32 add.o maths.o -o add

We’re done. I’ll be doing another one of these sorts of blog posts shortly demonstrating how we’ll do this in the 64-bit arena.

Pretty code is readable code

There’s no doubt about it. Syntax highlighting in code is the cornerstone of readability (in my mind anyway). I was browsing around today and found an assembly language highlighter for visual studio here.

Now my code looks like this (inside of VS).

Screen shot

Holy smoke!

Well, not really.

Nostalgia got the better of me today in the form of some good old mode 13 demo code. All the hours I’d blown previously developing little tid-bit apps like this and I never saved off any of my code. Thankfully, I have a good memory and whilst my assembly skills aren’t “top shelf”, they’re certainly up to the task of re-creating this sort of effect.

Smoke, Fire, Flame?

They’re all the same. They work of the same principal.

  • Set a palette that suits your effect (yellows, reds, orange for fire), (black to white for smoke)
  • Create some noise as far south as you can on the video buffer
  • Blur the pixels out on the screen making your resulting pixels ascend and decay

Easy!

On to the code …

So, I’ll present this little demo in a couple of chunks and explain them as I show them. The code is pretty well documented anyway so that reading it line for line should be very self-explanitory.

.model small
.stack 100h

.code
start:

	mov	ax, 0013h	; set 320x200x256 mode
	int	10h
	
	mov	ax, 0a000h	; we can't directly address ES so 
	mov	es, ax          ; we do so through AX. ES = A000
	
	call	setup_palette	; setup a palette with greyscale 
				; to support the smoke effect

no_kbhit:

	call	randomize_lines	; draw some random pixels 
	call	bloom		; average out the video buffer
	
	mov	ah, 01h		; test for a key press
	int	16h
	jz	no_kbhit	; continue running if no key was hit
	
	mov	ax, 0003h	; set text mode
	int	10h
	
	mov	ax, 4c00h	; return control back to dos
	int	21h

; -- subroutines removed for brevity

end start

end

This is the main program. It needs to drop us into the required video mode, make sure we don’t want to quit (i.e. was there a key hit?), actually perform the effect (the loop of random/average) and then clean up (send us back to text mode, return control to dos).

Giving the effect some colour

Setting up the palette in this type of routine really does determine the “type” of routine that it is. As I’d said above:

  • Purely greyscale will give you a smokey effect on screen
  • Gradients running through black, red, orange, yellow, white will give you fire/flame
  • Black, blue up to purple will give you a cool alcohol type fire
  • Greens will give you something alien

The idea is to experiment with palette creation to see what comes out best for you. Here’s how I setup a greyscale palette.

setup_palette:

	mov	cx, 255			; 256 colour indicies to set
	
next_colour_idx:
	mov	al, 255			; setup al so that we're setting
	sub	al, cl			; colour indicies from low to high
	
	mov	dx, 3c7h		; this port selects the colour index
					; that we'll set r,g,b for
	out	dx, al
	
	mov	dx, 3c9h		; this port sets the r,g,b components
						; for the selected index
							
	shr	al, 2			; rgb intensities are in range of 0..63
					; so, divide by 4 to adjust
							
	out	dx, al			; set the red
	out	dx, al			; set the green
	out	dx, al			; set the blue

	dec	cx			; move onto the next colour
	jnz	next_colour_idx
	
	ret

So, just a touch of VGA theory here. Unlike today’s video modes, the 256 colour VGA supported 256 indices that each had an RGB intensity set ranging (0..63) each. Sometime, I don’t know how we ever used this video mode, but we got by – and made some damn cool stuff using it. So, software port 3c7 takes a colour index. 3c8 can be used to read the colour intensities (not used in this program). 3c9 is the port we use to write (r,g,b) intensities. Dividing by 4 allows me to interpolate 0..255 against 0..63 so that 0 is the colour with least intensity up to 255 which has the greatest.

###(not so) Random

Getting psuedo random numbers with nothing in the toolbox is difficult. The method that I’ve used here is to constantly read from software port 40h which is tightly coupled with the timer interrupt but it keeps a fairly steady count. The uniformity of these numbers actually provides a very tame smoke effect, you’re not going to see much chaos.

randomize_lines:
	
	mov	cx, 640			; we're going to set two rows of pixels
					; at the bottom of the screen to be 
					; random colours, so that's 640 pixels
							
	mov	di, 63360		; we're going to start writing these 
					; pixels on the last two lines so that's
					; 64000 - 640
							
next_rand_pixel:

	mov	dx, 40h			; we get quasi-random values from port 40h
	in	al, dx
	
	stosb				; store the pixel on screen
	dec	cx			; move onto the next pixel
	jnz	next_rand_pixel
	
	ret

So, following along with the effect we only randomize the last two rows of the video array. Simple.

Airbrush, Airbrush!!

It’s just an averaging effect. We take the average of the current pixel, left, right and top most. We then re-set the pixel back into video memory 1 pixel above our current location. Therefore, we have no interest in trying to process the top-most row of video memory.

The only other part that is a little awkward to look at in this code block will be the ADC instructions. We’re dealing with bytes (values of 0..255). We’re adding 4 of these together so we’re going to quickly overflow a byte sized register. ADC (or add with carry adjustment) allows us to overflow this information into AX’s higher-order byte (AH). When it comes time to divide (or take the arithmetic average) of this pixel’s intensity, we’ll be able to perform this operation on the word sized AX register. Neat. Check it out:

bloom:

	mov	cx, 63680		; we average every pixel except the top row
	mov	di, 320			; we start at the 2nd row
	
next_avg:
	xor	ax, ax			; clear out our accumulator
	
	mov	al, es:[di]		; get the current pixel
	
	add	al, es:[di-1] 	; add the pixel to the left
	adc	ah, 0			; adjust for overflow
	
	add	al, es:[di+1] 	; add the pixel to the right
	adc	ah, 0			; adjust for overflow
	
	add	al, es:[di-320]	; add the pixel above
	adc	ah, 0			; adjust for overflow
	
	shr	ax, 2			; divide by 4 to get the average
	
	cmp	al, 0			; can we dampen?
	jz	no_damp			; jump over if we can't
	
	dec	al			; dampen the colour by 1
	
no_damp:
	mov	es:[di-320], al	; put the averaged pixel 1 pixel above
	
	inc	di			; next pixel
	dec	cx			; keep count of how many we've got left
	jnz	next_avg
	
	ret

So, when you put it all together (and run it in DosBox) you’ll get something that looks like this:

Smoke application running

Well.. I’m feeling all nostalgic now. Might go and fire up DosBox and play a couple of games of Double Dragon.

Beej's Tutorials

For such a long time I have read over these tutorials. They have been a great source of information in doing things the “unix way”.

Beej’s site http://beej.us

Beej’s Guide to Network Programming http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html

Beej’s Guide to Unix IPC http://beej.us/guide/bgipc/output/html/singlepage/bgipc.html

Beej’s Quick Guide to GDB http://beej.us/guide/bggdb/