Segmentation Fault when using Threads and Semaphores, Mac Vs Linux - multithreading

My problem deals with a segmentation fault that I get when I run this program on a linux machine versus my own mac computer. This program runs how I believe it should on my own mac computer, yet when I try to run it on my school's linux computers, I get a segmentation fault that doesn't appear on my mac computer. I'll give a brief background on the assignment and then go over the problem in more detail.
So I have this program which basically simulates baboons crossing a ravine with a single rope. Only one baboon can cross at a time and there are certain restraints on the number of baboons that can cross at a time, as well as how many baboons can cross from one direction before baboons from the other direction are allowed to cross. The implementation of the code.
I have searched for segmentation fault questions already here on stackoverflow, yet most of them deal with multiple processes whereas I am merely using different threads. The segmentation fault ends up coming from waiting on a semaphore that doesn't exist, yet when I checked to see whether it was initialized, it was successfully initialized. Again, this program works on my mac but then doesn't work when I try to run it on my Mac. Any help at all understanding why it can't run on the linux machines but can run on the mac. If any more information is needed, I would be happy to provide it. I did error check at one point but that code was deleted off the school computers. My error checking, as far as I remember, didn't show any errors.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>
#include <time.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/stat.h> //for mode flags, if needed for future use
#define ATOB_COUNT 20
#define BTOA_COUNT 20
#define RANDOM_SEED 2123
//semaphore names
#define MUTEX_SEM "/mutex"
#define TOB_SEM "/toB"
#define TOA_SEM "/toA"
//define methods here if needed
void *toAThread(void *threadId);
void *toBThread(void *threadId);
void my_sleep(int limit);
void sem_open_errorCheck(char *name, unsigned int startingValue, sem_t *result);
//defining semaphores and shared variables
sem_t *mutex, *toB, *toA;
int xingCount = 0;
int xedCount = 0;
int toBWaitCount = 0;
int toAWaitCount = 0;
enum xingDirectionTypes {
none,
aToB,
bToA
};
enum xingDirectionTypes xingDirection = none;
char orderLeaving[100];
struct threadInfo {
int threadId;
};
struct threadInfo atobIDs[ATOB_COUNT];
struct threadInfo btoaIDs[BTOA_COUNT];
int main(void) {
pthread_t atobPTHREADS[ATOB_COUNT];
pthread_t btoaPTHREADS[BTOA_COUNT];
pthread_attr_t attr;
void *status;
srandom(RANDOM_SEED);
//call helper method which creates semaphore and errorchecks
sem_open_errorCheck(MUTEX_SEM, (unsigned int)1, mutex);
sem_open_errorCheck(TOA_SEM, (unsigned int)0, toA);
sem_open_errorCheck(TOB_SEM, (unsigned int)0, toB);
//Creating a set of attributes to send to the threads
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
//spawn toB baboons
int counter;
for (counter = 0; counter < BTOA_COUNT; counter++) {
atobIDs[counter].threadId = counter;
int result;
if ((result = pthread_create(&atobPTHREADS[counter], &attr, toBThread, (void*) &atobIDs[counter])) == -1) {
perror("Thread Creation Error: atob baboon");
exit(EXIT_FAILURE);
}
}
//spawn toA baboons
for (counter = 0; counter < ATOB_COUNT; counter++) {
btoaIDs[counter].threadId = counter + 20;
int result;
if ((result = pthread_create(&btoaPTHREADS[counter], &attr, toAThread, (void*) &btoaIDs[counter])) == -1) {
perror("Thread Creation Error: btoa baboon");
exit(EXIT_FAILURE);
}
}
//Wait for all the threads to finish
for(counter = 0; counter < ATOB_COUNT; counter++)
{
int result = pthread_join(atobPTHREADS[counter], &status);
if(result == -1)
{
perror("Thread Join: AtoB");
exit(EXIT_FAILURE);
}
}
for(counter = 0; counter < BTOA_COUNT; counter++)
{
int result = pthread_join(btoaPTHREADS[counter], &status);
if(result == -1)
{
perror("Thread Join: BtoA");
exit(EXIT_FAILURE);
}
}
printf("The order leaving %s", orderLeaving);
exit(EXIT_SUCCESS);
}
void *toBThread(void *threadId) {
struct threadInfo *info;
info = (struct threadInfo *)threadId;
int id = info->threadId;
my_sleep(100); //simulate being idle for 1-100ms
//for order checking
char *baboonOrder;
baboonOrder = "B ";
strcat(orderLeaving, baboonOrder);
sem_wait(mutex);
if ((xingDirection == aToB || xingDirection == none) && xingCount < 5 && (xedCount + xingCount) < 10) { //there is an extra parenthesis here in the solutions
xingDirection = aToB;
xingCount++;
printf("AtoB baboon (thread %d) got on the rope\n", id);
sem_post(mutex);
}
else {
toBWaitCount++;
sem_post(mutex);
sem_wait(toB);
toBWaitCount--;
xingCount++;
xingDirection = aToB;
printf("AtoB baboon (thread %d) got on the rope\n", id);
sem_post(mutex);
}
//CROSSING
sem_wait(mutex);
printf("AtoB baboon (thread %d) got off the rope\n", id);
xedCount++;
xingCount--;
if (toBWaitCount != 0 && (((xedCount+xingCount)<10) || ((xedCount+xingCount) >= 10 && toAWaitCount == 0))) {
sem_post(toB);
}
else {
if (xingCount == 0 && toAWaitCount != 0 && (toBWaitCount == 0 || (xedCount + xingCount)>=10)) {
xingDirection = bToA;
xedCount = 0;
sem_post(toA);
}
else {
if (xingCount == 0 && toBWaitCount == 0 && toAWaitCount == 0) {
xingDirection = none;
xedCount = 0;
sem_post(mutex);
}
else {
sem_post(mutex);
}
}
}
}
/*
baboons going from side a to side b
*/
void *toAThread(void *threadId) {
struct threadInfo *info;
info = (struct threadInfo *)threadId;
int id = info->threadId;
my_sleep(100);
//for order checking
char *baboonOrder;
baboonOrder = "A ";
strcat(orderLeaving, baboonOrder);
sem_wait(mutex);
if ((xingDirection == bToA || xingDirection == none) && xingCount < 5 && (xedCount + xingCount) < 10) { //there is an extra parenthesis here in the solutions
xingDirection = bToA;
xingCount++;
printf("BtoA baboon (thread %d) got on the rope\n", id);
sem_post(mutex);
}
else {
toAWaitCount++;
sem_post(mutex);
sem_wait(toA);
toAWaitCount--;
xingCount++;
xingDirection = bToA;
printf("BtoA baboon (thread %d) got on the rope\n", id);
sem_post(mutex);
}
//CROSSING
sem_wait(mutex);
printf("BtoA baboon (thread %d) got off the rope\n", id);
xedCount++;
xingCount--;
if (toAWaitCount != 0 && (((xedCount+xingCount)<10) || ((xedCount+xingCount) >= 10 && toBWaitCount == 0))) {
sem_post(toA);
}
else {
if (xingCount == 0 && toBWaitCount != 0 && (toAWaitCount == 0 || (xedCount + xingCount)>=10)) {
xingDirection = aToB;
xedCount = 0;
sem_post(toB);
}
else {
if (xingCount == 0 && toAWaitCount == 0 && toBWaitCount == 0) {
xingDirection = none;
xedCount = 0;
sem_post(mutex);
}
else {
sem_post(mutex);
}
}
}
}
//taken with permission from readers/writers problem
//Puts the calling thread to sleep to simulate both random start times and random workloads
void my_sleep(int limit) {
struct timespec time_ns;
int duration = random() % limit + 1;
time_ns.tv_sec = 0;
time_ns.tv_nsec = duration * 1000000;
int result = nanosleep(&time_ns, NULL);
if (result != 0)
{
perror("Nanosleep");
exit(EXIT_FAILURE);
}
}
void sem_open_errorCheck(char *name, unsigned int startingValue, sem_t *result) {
sem_unlink(name);
result = sem_open(name, O_CREAT, 0600, startingValue);
if (result == -1) {
perror("sem_open error: semaphore failed to open correctly");
exit(EXIT_FAILURE);
}
}

How to debug stuff like this
The best way to debug this is to run it using the gdb debugger. Like this:
gdb my-monkey-program
(gdb) run
Program received signal SIGSEGV, Segmentation fault.
(gdb) info threads
(gdb) bt
Another excellent idea is to run it with valgrind:
valgrind ./my-monkey-program
which will tell you about invalid memory accesses and all sorts of things.
Your specific problem
gdb reports that the call stack is:
#0 sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:45
#1 0x0000000000400e8d in toAThread (threadId=0x602160) at test.c:190
#2 0x00007ffff7bc4e9a in start_thread (arg=0x7fffed7e9700) at pthread_create.c:308
#3 0x00007ffff78f1cbd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
#4 0x0000000000000000 in ?? ()
Here are the line numbers from my compile:
187 baboonOrder = "A ";
188 strcat(orderLeaving, baboonOrder);
189
190 sem_wait(mutex);
This is because mutex is NULL.
Why it breaks
You're never actually assigning to the mutex variable. You're passing a pointer into sem_open_errorCheck, but what you really need to pass is a pointer-to-a-pointer. Presumably the same applies to toA and toB.
It's just luck that it worked on the Mac!

Related

Named Pipe, Communication between 2 children

I have a problem with my code. I want to make communication between 2 children process. One of them is a server, which opens a file and sends each letter to the second process. The second process is counting letters and it should make a new file and save results. I have problems with the last step because the first process gonna finish faster than the second, what causes the end of the program. I have no idea how fix it. Looking for some tips :).
Here you got result.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
//stale
#define FIFO "my_fifo"
#define SIZE 26
//zmienne globalne
int desk; //deskryptor pliku
int tab[SIZE];
//prototypy funkcji
void parentKillAll();
void server(FILE * file);
void client();
void cleanUp(FILE * file);
int checkEntryData(int argc, char *argv);
void replaceTabWithZero(int * tab);
void countLetters(int * tab, char ch);
void saveResults(int * tab, char *title);
void showTab(int * tab);
int main(int argc, char *argv[]) {
if (!checkEntryData(argc, argv[1]))
return 1;
replaceTabWithZero(tab);
FILE *file = fopen(argv[1], "r");
umask(0);
mkfifo(FIFO, 0666);
if (file) {
if (fork() == 0) {
server(file);
exit(0);
} else if (fork() == 0) {
client();
saveResults(tab, strcat(argv[1], "Result"));
showTab(tab);
exit(0);
} else {
cleanUp(file);
parentKillAll();
}
} else {
perror("Error");
}
return 0;
}
void parentKillAll() {
sleep(1);
kill(0, SIGKILL);
exit(0);
}
void server(FILE * file) {
char ch;
while ((ch = fgetc(file)) != EOF) {
desk = open(FIFO, O_WRONLY);
write(desk, &ch, 1);
}
}
void client() {
char ch;
while (1) {
desk = open(FIFO, O_RDONLY);
read(desk, &ch, 1);
countLetters(tab, ch);
printf("%c", ch);
}
}
void cleanUp(FILE *file) {
wait(0);
fclose(file);
close(desk);
}
int checkEntryData(int argc, char *argv) {
if (argc < 2) {
fprintf(stderr, "Nie poprawna ilosc argumentow\n");
return 0;
}
if (access(argv, F_OK)) {
fprintf(stderr, "Podany plik \'%s\' nie istnieje\n", argv);
return 0;
}
if (access(argv, R_OK)) {
fprintf(stderr, "Brak uprawnien do odczytu pliku \'%s\'\n", argv);
return 0;
}
return 1;
}
void replaceTabWithZero(int * tab) {
for (int i = 0; i < SIZE; i++)
tab[i] = 0;
}
void countLetters(int *tab, char ch) {
int chVal = ch;
if (chVal > 92)
chVal -= 32;
if (chVal > 64 && chVal < 91)
tab[chVal-65] += 1;
}
void saveResults(int *tab, char * title) {
FILE *plik = fopen(title, "w");
if (plik) {
for (int i = 0; i < SIZE; i++)
fprintf(plik, "%c - %d\n", (i+97), tab[i]);
} else {
perror("Error");
}
fclose(plik);
}
void showTab(int * tab) {
for (int i = 0; i < SIZE; i++)
printf("\n%d", tab[i]);
}
The real problem is that the client process can never finish, because it runs an infinite while(1) loop without any exit conditions.
You should rewrite it so that it exits after reading all available data:
void client() {
char ch;
// Open the fifo only once, instead of once per character
desk = open(FIFO, O_RDONLY);
// Loop until there is no more data to read
while(read(desk, &ch, 1) > 0) {
countLetters(tab, ch);
printf("%c", ch);
}
}
This is technically sufficient to make it work, but you should also look into a series of other issues:
You should have two wait(0) calls so that you wait for both processes, and you shouldn't try to kill anything.
The server process should only be opening the fifo once, not once per character.
You should be comparing fgetc output to EOF before forcing the value into a char. Since you do it after, running your program on a ISO-8859-1 terminal will cause it to confuse EOF and the letter ΓΏ
You are using strcat on argv[1], even though you don't know how much space that array has. You should use your own buffer of a known length.
You should check the return value of all your system calls to ensure they succeed. Checking with access and then assuming it'll be fine is not as good since calls can fail for other reasons.
Canonical Unix behavior is to exit with 0 for success, and >= 1 for error.
It's good practice to use a larger buffer (e.g. 65536 bytes instead of 1) when using read/write directly. stdio functions like fgetc already uses a larger buffer behind the scenes.
Using a named pipe obviously works, but since you spawn both processes it would be more natural to use an unnamed one.

My semaphore module is not working properly(Dining philosopher)

I'm implementing a semaphore methods to understand synchronization and thread things.
By using my semaphore, I tried to solve the Dining Philosophers problem.
My plan was making deadlock situation first.
But I found that just only one philosopher eat repeatedly.
And I checked that my semaphore is working quite good by using other synchronization problems. I think there is some problem with grammar.
please let me know what is the problem.
Here is my code.
dinig.c (including main function)
#include "sem.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static tsem_t *chopstick[5];
static tsem_t *updating;
static int update_status (int i, int eating)
{
static int status[5] = { 0, };
static int duplicated;
int idx;
int sum;
tsem_wait (updating);
status[i] = eating;
/* Check invalid state. */
duplicated = 0;
sum = 0;
for (idx = 0; idx < 5; idx++)
{
sum += status[idx];
if (status[idx] && status[(idx + 1) % 5])
duplicated++;
}
/* Avoid printing empty table. */
if (sum == 0)
{
tsem_signal (updating);
return 0;
}
for (idx = 0; idx < 5; idx++)
fprintf (stdout, "%3s ", status[idx] ? "EAT" : "...");
/* Stop on invalid state. */
if (sum > 2 || duplicated > 0)
{
fprintf (stdout, "invalid %d (duplicated:%d)!\n", sum, duplicated);
exit (1);
}
else
fprintf (stdout, "\n");
tsem_signal (updating);
return 0;
}
void *thread_func (void *arg)
{
int i = (int) (long) arg;
int k = (i + 1) % 5;
do
{
tsem_wait (chopstick[i]);
tsem_wait (chopstick[k]);
update_status (i, 1);
update_status (i, 0);
tsem_signal (chopstick[i]);
tsem_signal (chopstick[k]);
}
while (1);
return NULL;
}
int main (int argc,
char **argv)
{
int i;
for (i = 0; i < 5; i++)
chopstick[i] = tsem_new (1);
updating = tsem_new (1);
for (i = 0; i < 5; i++)
{
pthread_t tid;
pthread_create (&tid, NULL, thread_func, (void *) (long) i);
}
/* endless thinking and eating... */
while (1)
usleep (10000000);
return 0;
}
sem.c(including semaphore methods)
#include "sem.h"
.
sem.h(Header for sem.c)
#ifndef __SEM_H__
#define __SEM_H__
#include <pthread.h>
typedef struct test_semaphore tsem_t;
tsem_t *tsem_new (int value);
void tsem_free (tsem_t *sem);
void tsem_wait (tsem_t *sem);
int tsem_try_wait (tsem_t *sem);
void tsem_signal (tsem_t *sem);
#endif /* __SEM_H__ */
compile command
gcc sem.c dining.c -pthread -o dining
One problem is that in tsem_wait() you have the following code sequence outside of a lock:
while(sem->count <= 0)
continue;
There's no guarantee that the program will actually re-read sem->count - the compiler is free to produce machine code that does something like the following:
int temp = sem->count;
while(temp <= 0)
continue;
In fact, this will likely happen in an optimized build.
Try changing your busy wait loop to something like this so the count is checked while holding the lock:
void tsem_wait (tsem_t *sem)
{
pthread_mutex_lock(&(sem->mutexLock));
while (sem->count <= 0) {
pthread_mutex_unlock(&(sem->mutexLock));
usleep(1);
pthread_mutex_lock(&(sem->mutexLock));
}
// sem->mutexLock is still held here...
sem->count--;
pthread_mutex_unlock(&(sem->mutexLock));
}
Strictly speaking, you should do something similar for tsem_try_wait() (which you're not using yet).
Note that you might want to consider using a pthread_cond_t to make waiting on the counter changing more efficient.
Finally, your code to 'get' the chopsticks in thread_func() has the classic Dining Philosopher deadlock problem in the situation where each philosopher simultaneously acquires the 'left' chopstick (chopstick[i]) and ends up waiting forever to get the 'right' chopstick (chopstick[k]) since all the chopsticks are in some philosopher's left hand.

Cygwin: interrupting blocking read

I've written the program which spawns a thread that reads in a loop from stdin in a blocking fashion. I want to make the thread return from blocked read immediately. I've registered my signal handler (with sigaction and without SA_RESTART flag) in the reading thread, send it a signal and expect read to exit with EINTR error. But it doesn't happen. Is it issue or limitation of Cygwin or am I doing something wrong?
Here is the code:
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
pthread_t thread;
volatile int run = 0;
void root_handler(int signum)
{
printf("%s ENTER (thread is %x)\n", __func__, pthread_self());
run = 0;
}
void* thr_func(void*arg)
{ int res;
char buffer[256];
printf("%s ENTER (thread is %x)\n", __func__, pthread_self());
struct sigaction act;
memset (&act, 0, sizeof(act));
act.sa_sigaction = &root_handler;
//act.sa_flags = SA_RESTART;
if (sigaction(SIGUSR1, &act, NULL) < 0) {
perror ("sigaction error");
return 1;
}
while(run)
{
res = read(0,buffer, sizeof(buffer));
if(res == -1)
{
if(errno == EINTR)
{
puts("read was interrupted by signal");
}
}
else
{
printf("got: %s", buffer);
}
}
printf("%s LEAVE (thread is %x)\n", __func__, pthread_self());
}
int main() {
run = 1;
printf("root thread: %x\n", pthread_self());
pthread_create(&thread, NULL, &thr_func, NULL);
printf("thread %x started\n", thread);
sleep(4);
pthread_kill(thread, SIGUSR1 );
//raise(SIGUSR1);
pthread_join(thread, NULL);
return 0;
}
I'm using Cygwin (1.7.32(0.274/5/3)).
I've just tried to do the same on Ubuntu and it works (I needed to include signal.h, though, even though in Cygwin it compiled as it is). It seems to be peculiarity of Cygwin's implementation.

Message queue/shared memory method

I have a bit of a problem in using IPC (inter-process communication) program below.
Please let me explain:
I want to pass Linux commands such as "ls" or "wc file.txt"
from a parent to a child to execute using the message queue, and
then have the child returning the command outputs back to
the parent process using shared memory method.
But this is what I got: The parent process always got the output 1 step behind;
in the following fashion:
Step1) ls file.txt
(Nothing showed up.)
Step2) wc file.txt
(Output of earlier command "ls file.txt" showed up here instead.)
Step 3) cat file.txt
(Output of earlier command "wc file.txt" showed up instead.)
Any help is appreciated.
To compile: gcc -o program ./program.c
To run: -./program -v
Code:
#define BUFSZ 512
#define ERRBUFSZ 512
#define TIMEOUT_TIMEDIO 20
#define SHM_SIZE 5120
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
static sigjmp_buf jmpbuf;
int timed_io(char* buf, int len, FILE* rfp, int sec);
static void sigalrm_handler(int signo);
void do_cmd(char *buf, int len, int linenum, char *errbuf);
int parse_cmd(char *buf, char **vbuf, char *errbuf);
int process_cmd_ipc(char *argv, int linenum, char *errbuf);
struct my_msgbuf {
long mtype;
char mtext[256];
};
static void sigalrm_handler(int signo)
{
siglongjmp(jmpbuf, 1);
}
int timed_io(char* buf, int len, FILE* rfp, int sec)
{
struct sigaction nsigaction[1];
struct sigaction osigaction[1];
int prev_alrm;
int st = 0;
if(sigsetjmp(jmpbuf, 1) == 0)
{
nsigaction->sa_handler = sigalrm_handler;
sigemptyset(&nsigaction->sa_mask);
nsigaction->sa_flags = SA_RESTART;
prev_alrm = alarm(0);
sigaction(SIGALRM, nsigaction, osigaction);
alarm(sec);
if (fgets(buf, len, rfp) == NULL)
st = -1; // EOF
buf[strlen(buf) - 1] = 0;
}
else { st = -2; } // Time-out
alarm(0); // Reset old alarm and handler
sigaction(SIGALRM, osigaction, 0);
return st;
}
int process_cmd_ipc(char *argv, int linenum, char* errbuf)
{
struct my_msgbuf buf;
int msqid, msqid_parent, st, shmid, str_len;
key_t key, key_shm;
char* shared_buf;
FILE *fd;
// create key for shared memory segment
if ((key_shm = ftok("shm_key.txt", 'R')) == -1) {
perror("ftok");
exit(1);
}
// Connect to shared memory segment
if ((shmid = shmget(key_shm, SHM_SIZE, 0644 | IPC_CREAT)) == -1)
{
perror("shmget");
exit(1);
}
// Attach to shared memory segment
shared_buf = shmat(shmid, (void *) 0, 0);
if (shared_buf == (char *) (-1)) {
perror("shmat");
exit(1);
}
// End of shared memory section` //
// Begin: message queue section
pid_t cpid=fork();
if (cpid<0) {
fprintf(stderr,"ERR: \"fork\" error! (Line=%d)\n", linenum);
exit (-1);
} else if (cpid==0) // child process
{ // Begin: message queue
if ((key = ftok("mysh.c", 'B')) == -1) {
perror("ftok");
exit(1);
}
if ((msqid = msgget(key, 0644)) == -1) {
perror("msgget from child");
exit(1);
}
memset(buf.mtext, 0, sizeof(buf.mtext)); // Clear buffer
if(msgrcv(msqid, (struct msgbuf*) &buf, sizeof(buf), 0,0) == -1)
{
perror("msgrcv");
exit(1);
}
// End: message queue
// begin: shared memory segment
memset(shared_buf, 0, SHM_SIZE); // zeroize shared_buf
fd = popen(buf.mtext, "r");
str_len = 0;
while(fgets(shared_buf + str_len, SHM_SIZE, fd) != NULL)
{ str_len = strlen(shared_buf); }
pclose(fd);
// end: shared memory segment
}
else { // parent
// Begin - message queue
if ((key = ftok("mysh.c", 'B')) == -1) {
perror("ftok");
exit(1);
}
if ((msqid_parent = msgget(key, 0644 | IPC_CREAT)) == -1) {
perror("msgget from parent");
exit(1);
}
buf.mtype = 1;
strncpy(buf.mtext, argv, strlen(argv));
if(msgsnd(msqid_parent, (struct my_msgbuf*) &buf, strlen(buf.mtext), 0) == -1)
perror("msgsnd");
// End - message queue
// Begin - shared memory
// usleep(10000);
printf("%s", shared_buf);
// End - shared memory
} // if-else fork
}
int parse_cmd(char *buf, char **vbuf, char *errbuf)
{
int i=0;
char *delim=" ,\t\n";
char *tok;
tok=strtok(buf,delim);
while (tok) {
vbuf[i]=(char *)malloc(BUFSZ*sizeof(char));
strcpy(vbuf[i],tok);
tok=strtok(NULL,delim);
i++;
}
vbuf[i]=0;
return i;
}
void do_cmd(char *buf, int len, int linenum, char *errbuf) {
int i=0; int numargs;
char *vbuf[128];
char* copy = (char *) malloc(strlen(buf) + 1);
int maxargs=sizeof(vbuf)/sizeof(char *);
strcpy(copy, buf);
numargs = parse_cmd(copy,vbuf,errbuf);
process_cmd_ipc(buf,linenum, errbuf);
for (i=0;i<numargs; i++) { free(vbuf[i]); }
free(copy);
copy = NULL;
return;
}
int main(int argc, char **argv)
{
int i; int st; int linenum=0;
char *buf=(char *)malloc(BUFSZ*sizeof(char));
char *errbuf=(char *)malloc(ERRBUFSZ*sizeof(char));
char *mysh = "";
FILE *rfp=stdin;
if (isatty(fileno(rfp))) {
mysh = "mysh (Ctrl-C to exit)>";
fprintf(stderr,"%s",mysh);
}
while(1)
{
st = timed_io(buf, BUFSZ, stdin, TIMEOUT_TIMEDIO);
if (st != 0)
{
fprintf(stderr, "ERR: No input %s (Status=%d)\n", errbuf, st);
return -1;
}
else
{
linenum++;
if (*buf)
{ do_cmd(buf, BUFSZ, linenum,errbuf); }
if (mysh)
fprintf(stderr,"%s",mysh);
}
}
}

NUMA Memory Page Migration Overhead

I have to find the overhead associated with NUMA memory page migration under Linux.
Can you please tell me which tools I can use?
If possible could you show an example.
If you want to understand whether your system is doing excessive remote node memory accesses and you're using intel CPUs, Intel's PMU has a utility called vtbwrun to report the QPI/uncore activity.
If you want to see how long it takes to execute a page migration, you can measure the duration of calls to numa_move_pages (provided by the numactl package).
Here's an example:
/*
* Test program to test the moving of a processes pages.
*
* (C) 2006 Silicon Graphics, Inc.
* Christoph Lameter <clameter#sgi.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include "../numa.h"
#include <unistd.h>
#include <errno.h>
unsigned int pagesize;
unsigned int page_count = 32;
char *page_base;
char *pages;
void **addr;
int *status;
int *nodes;
int errors;
int nr_nodes;
struct bitmask *old_nodes;
struct bitmask *new_nodes;
int main(int argc, char **argv)
{
int i, rc;
pagesize = getpagesize();
nr_nodes = numa_max_node()+1;
old_nodes = numa_bitmask_alloc(nr_nodes);
new_nodes = numa_bitmask_alloc(nr_nodes);
numa_bitmask_setbit(old_nodes, 1);
numa_bitmask_setbit(new_nodes, 0);
if (nr_nodes < 2) {
printf("A minimum of 2 nodes is required for this test.\n");
exit(1);
}
setbuf(stdout, NULL);
printf("migrate_pages() test ......\n");
if (argc > 1)
sscanf(argv[1], "%d", &page_count);
page_base = malloc((pagesize + 1) * page_count);
addr = malloc(sizeof(char *) * page_count);
status = malloc(sizeof(int *) * page_count);
nodes = malloc(sizeof(int *) * page_count);
if (!page_base || !addr || !status || !nodes) {
printf("Unable to allocate memory\n");
exit(1);
}
pages = (void *) ((((long)page_base) & ~((long)(pagesize - 1))) + pagesize);
for (i = 0; i < page_count; i++) {
if (i != 2)
/* We leave page 2 unallocated */
pages[ i * pagesize ] = (char) i;
addr[i] = pages + i * pagesize;
nodes[i] = 1;
status[i] = -123;
}
/* Move to starting node */
rc = numa_move_pages(0, page_count, addr, nodes, status, 0);
if (rc < 0 && errno != ENOENT) {
perror("move_pages");
exit(1);
}
/* Verify correct startup locations */
printf("Page location at the beginning of the test\n");
printf("------------------------------------------\n");
numa_move_pages(0, page_count, addr, NULL, status, 0);
for (i = 0; i < page_count; i++) {
printf("Page %d vaddr=%p node=%d\n", i, pages + i * pagesize, status[i]);
if (i != 2 && status[i] != 1) {
printf("Bad page state before migrate_pages. Page %d status %d\n",i, status[i]);
exit(1);
}
}
/* Move to node zero */
numa_move_pages(0, page_count, addr, nodes, status, 0);
printf("\nMigrating the current processes pages ...\n");
rc = numa_migrate_pages(0, old_nodes, new_nodes);
if (rc < 0) {
perror("numa_migrate_pages failed");
errors++;
}
/* Get page state after migration */
numa_move_pages(0, page_count, addr, NULL, status, 0);
for (i = 0; i < page_count; i++) {
printf("Page %d vaddr=%lx node=%d\n", i,
(unsigned long)(pages + i * pagesize), status[i]);
if (i != 2) {
if (pages[ i* pagesize ] != (char) i) {
printf("*** Page contents corrupted.\n");
errors++;
} else if (status[i]) {
printf("*** Page on the wrong node\n");
errors++;
}
}
}
if (!errors)
printf("Test successful.\n");
else
printf("%d errors.\n", errors);
return errors > 0 ? 1 : 0;
}

Resources