Message queues are pretty common structures for inter-process communication. A common queue is created by one of the processes, from there it can be connected to by any other process and have messages submitted to it.
This snippet shows the creation of a queue and sending a message. Another block below this will show receiving a message from the queue.
charbuf[20];intmsqid;key_tkey;/* --- message sender --- *//* make a key */key=ftok("first",'B');/* create the message queue */msqid=msgget(key,0644|IPC_CREAT));/* put a message onto the queue */msgsnd(msqid,&buf,20,0);/* destroy (remove) the message queue */msgctl(msqid,IPC_RMID,NULL);/* --- message receiver --- *//* make a key */key=ftok("second",'B');/* connect to the message queue */msqid=msgget(key,0644);/* receive the message off the queue */msgrcv(msqid,&buf,20,0,0);
This snippet will show you how to open a file and map it into memory.
intfd,pagesize;char*data;/* open the file */fd=open("somefile",O_RDONLY);/* get the current page size */pagesize=getpagesize();/* map the 2nd page into memory */data=mmap((caddr_t)0,pagesize,PROT_READ,MAP_SHARED,fd,pagesize);/* start using the data pointer */
Locking a file helps assure your program that no other processes can tamper with it or a region of it.
This snippet will show you how to lock and unlock a file.struct flock fl;
int fd;
/* fill out the lock structure */fl.l_type=F_WRLCK;fl.l_whence=SEEK_SET;fl.l_start=0;fl.l_len=0;fl.l_pid=getpid();/* open the file */fd=open("filename",O_WRONLY);/* lock the file */fcntl(fd,F_SETLKW,&fl);/* --- complete any work here with the file locked --- *//* unlock the file now */fl.l_type=F_UNLCK;fcntl(fd,F_SETLK,&fl);
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_tpid=fork();intchild_exit_code;if(pid<0){/* -1 indicates that fork failed */exit(1);}elseif(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);}
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 */intadd(int,int);intmain(){/* add some numbers */intx=add(5,4);/* print the result out */printf("5+4=%d\n",x);return0;}
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.
globaladdsection.textadd:moveax,[esp+4]; get the 1st parammovecx,[esp+8]; get the 2nd paramaddeax,ecx; add them together; leaving the return value in eaxret
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.