I installed Arch Arm onto an Rpi3, then rsync'd sysroot to an x86_64 Arch Linux installed on a Lenovo thinkpad.
I then installed the arm-linux-gnueabihf Linaro cross compiler
To avoid any problems I used absolute paths in compilation:
/home/sameh/Rpi/Compiler/gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc\
--sysroot=/home/sameh/Rpi/Arch/ArmV7/root\
-o stress stress.c -lm
The code compiles fine, however when I execute it on the Rpi3 it has no output.
It doesn't freez the Pi, I can ps aux and see the child processes created by fork().
But none of the debug statements are printed and none of the processes exit.
Edit
This code is based on the stress library. For an MCVE I minimized it to only the hogcpu function
#include <ctype.h>
#include <errno.h>
#include <libgen.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
int hogcpu (void);
int
hogcpu (void)
{
for(int i=0; i < 1000000; i++)
sqrt (rand ());
return 0;
}
int main()
{
struct timespec start, end;
double cpu_time_used;
int pid, children = 0, retval = 0;
long forks;
int do_dryrun = 0;
long long do_backoff = 3000;
long long do_cpu = 1;
long long backoff, timeout = 0;
/* Calculate the backoff value so we get good fork throughput. */
backoff = do_backoff * forks;
clock_gettime(CLOCK_REALTIME, &start);
while ((forks = (do_cpu + do_io + do_vm + do_hdd)))
{
if (do_cpu)
{
switch (pid = fork ())
{
case 0: /* child */
alarm (timeout);
usleep (backoff);
exit (hogcpu ());
case -1: /* error */
break;
default:
++children;
}
--do_cpu;
}
}
/* Wait for our children to exit. */
while (children)
{
int status, ret;
if ((pid = wait (&status)) > 0)
{
--children;
if (WIFEXITED (status))
{
if ((ret = WEXITSTATUS (status)) == 0)
{
printf( "<-- worker %i returned normally\n", pid);
}
else
{
printf( "<-- worker %i returned error %i\n", pid, ret);
++retval;
printf( "now reaping child worker processes\n");
if (signal (SIGUSR1, SIG_IGN) == SIG_ERR)
printf( "handler error: %s\n", strerror (errno));
if (kill (-1 * getpid (), SIGUSR1) == -1)
printf( "kill error: %s\n", strerror (errno));
}
}
}
}
clock_gettime(CLOCK_REALTIME, &end);
cpu_time_used = (end.tv_nsec = start.tv_nsec) / 1000000000.0;
/* Print final status message. */
if (retval)
{
printf( "failed run completed in %.2f s\n", cpu_time_used);
}
else
{
printf( "successful run completed in -- %.2f s\n", cpu_time_used);
}
exit (retval);
}
I can successfully compile and execute it on the the Pi with:
[alarm#control ~]$ gcc stress.c -o stress -lm
[alarm#control ~]$ ./stress
<-- worker 16834 returned normally
<-- worker 16835 returned normally
<-- worker 16836 returned normally
successful run completed in -- 0.90 s
However, when cross compiled and transferred to the Pi, the behavior described above is what I am seeing.
Note
This may well have to do with the clock_gettime call. When I replace this with a clock() function call, I can compile and run it on the laptop, but compiling on the Pi with gcc has the same behavior above.
When using clock_gettime and compiling on the Pi, it works fine.
The issue here was how the long forks; variable was initialized. I am not well versed in compilers, but because forks was not initialized, the calculation backoff = do_backoff * forks; resulted in a random negative number.
This blocked the call usleep (backoff); from finishing. So initializing forks to 1 fixed the problem.
I would have thought that forks should have been initialized to 0 by the compiler as past of the bss_data so I am not sure why it didn't. Probably need more research into that part, but the code executes fine now with cross compiling.
Related
I want to protect a function from multithreaded access. For that purpose I am using a pthread_mutex_t mutex. I try to lock it in the beginning of a function, then execute the function, then release it again. If the mutex is in use it should wait for at maximum 60 seconds for it to be come available. If after that it is still not available, the function should fail.
The problem I'm having is it that pthread_mutex_timedlock seems to completely ignore the timeout value I'm giving it. Although I specify a timeout of 60 seconds, if the lock is taken, the function returns immediately with the error code ETIMEDOUT -- without actually waiting.
Here is a minimal example which reproduces the problem. In this case it does not matter whether I'm using recursive or non-recursive mutexes, since I'm not trying to lock them multiple times from the same thread.
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stddef.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <pthread.h>
pthread_mutex_t lock; /* exclusive lock */
//do some work to keep the processor busy..
int wut() {
int x = 0;
for(int i=0; i < 1024*1024*1024; i++)
x += 1;
return x;
}
void InitMutex(){
/*pthread_mutexattr_t Attr;
pthread_mutexattr_init(&Attr);
pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&lock, &Attr);*/
pthread_mutex_init(&lock, NULL);
}
//lock mutex, wait at maximum 60 seconds, return sucesss
int LockMutex() {
struct timespec timeoutTime;
timeoutTime.tv_nsec = 0;
timeoutTime.tv_sec = 60;
printf("Nanoseconds: %lu, seconds %lu\n", timeoutTime.tv_nsec, timeoutTime.tv_sec);
int retVal = pthread_mutex_timedlock(&lock, &timeoutTime);
printf("pthread_mutex_timedlock(): %d\n", retVal);
if(retVal != 0) {
const char* errVal = NULL;
switch(retVal) {
case EINVAL: errVal = "EINVAL"; break;
case EAGAIN: errVal = "EAGAIN"; break;
case ETIMEDOUT: errVal = "ETIMEDOUT"; break;
case EDEADLK: errVal = "EDEADLK"; break;
default: errVal = "unknown.."; break;
}
printf("Error taking lock in thread %lu: %s (%s)\n", pthread_self(), errVal , strerror(retVal));
}
return retVal == 0; //indicate success/failure
}
void UnlockMutex() {
pthread_mutex_unlock(&lock);
}
void TestLockNative() {
uint64_t thread_id = pthread_self();
printf("Trying to take lock in thread %lu.\n", thread_id);
int ret = LockMutex();
printf("Got lock in thread %lu. sucess=%d\n", thread_id, ret);
wut();
printf("Giving up lock now from thread %lu.\n", thread_id);
UnlockMutex();
}
void* test_thread(void* arg) {
//TestLock();
TestLockNative();
return NULL;
}
int main() {
InitMutex();
//create two threads which will try to access the protected function at once
pthread_t t1, t2;
pthread_create(&t1, NULL, &test_thread, NULL);
pthread_create(&t2, NULL, &test_thread, NULL);
//wait for threads to end
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}
The output of the program is e.g.:
Trying to take lock in thread 139845914396416.
Nanoseconds: 0, seconds 6000
pthread_mutex_timedlock(): 0
Got lock in thread 139845914396416. sucess=1
Trying to take lock in thread 139845906003712.
Nanoseconds: 0, seconds 6000
pthread_mutex_timedlock(): 110
Error taking lock in thread 139845906003712: ETIMEDOUT (Connection timed out) [<-- this occurs immediately, not after 60 seconds]
Got lock in thread 139845906003712. sucess=0
Giving up lock now from thread 139845906003712.
Compilation with gcc -o test test.c -lpthread should work.
So, does anyone know what's going on here and why pthread_mutex_timedlock() ignores my timeout value? It does not behave the way it is documented at all.
I'm using a Ubuntu 16.04.2 LTS system, compiling with gcc.
The manual page for pthread_mutex_timedlock says:
The timeout shall expire when the absolute time specified by abstime passes, as measured
by the clock on which timeouts are based
Therefore, use real time to specify your timeout value:
int LockMutex() {
struct timespec timeoutTime;
clock_gettime(CLOCK_REALTIME, &timeoutTime);
timeoutTime.tv_sec += 60;
int retVal = pthread_mutex_timedlock(&lock, &timeoutTime);
....
In the context of an existing multi-threaded application I want to suspend a list of threads for a specific duration then resume their normal execution. I know some of you wil say that I should not do that but I know that and I don't have a choice.
I came up with the following code that sort of work but randomly failed. For each thread I want to suspend, I send a signal and wait for an ack via a semaphore. The signal handler when invoked, post the semaphore and sleep for the specified duration.
The problem is when the system is fully loaded, the call to sem_timedwait sometimes fails with ETIMEDOUT and I am left with an inconsistent logic with semaphore used for the ack: I don't know if the signal has been dropped or is just late.
// compiled with: gcc main.c -o test -pthread
#include <pthread.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/syscall.h>
#define NUMTHREADS 40
#define SUSPEND_SIG (SIGRTMIN+1)
#define SUSPEND_DURATION 80 // in ms
static sem_t sem;
void checkResults(const char *msg, int rc) {
if (rc == 0) {
//printf("%s success\n", msg);
} else if (rc == ESRCH) {
printf("%s failed with ESRCH\n", msg);
} else if (rc == EINVAL) {
printf("%s failed with EINVAL\n", msg);
} else {
printf("%s failed with unknown error: %d\n", msg, rc);
}
}
static void suspend_handler(int signo) {
sem_post(&sem);
usleep(SUSPEND_DURATION*1000);
}
void installSuspendHandler() {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = suspend_handler;
int rc = sigaction(SUSPEND_SIG, &sa, NULL);
checkResults("sigaction SUSPEND", rc);
}
void *threadfunc(void *param) {
int tid = *((int *) param);
free(param);
printf("Thread %d entered\n", tid);
// this is an example workload, the real app is doing many things
while (1) {
int rc = sleep(30);
if (rc != 0 && errno == EINTR) {
//printf("Thread %d got a signal delivered to it\n", tid);
} else {
//printf("Thread %d did not get expected results! rc=%d, errno=%d\n", tid, rc, errno);
}
}
return NULL;
}
int main(int argc, char **argv) {
pthread_t threads[NUMTHREADS];
int i;
sem_init(&sem, 0, 0);
installSuspendHandler();
for(i=0; i<NUMTHREADS; ++i) {
int *arg = malloc(sizeof(*arg));
if ( arg == NULL ) {
fprintf(stderr, "Couldn't allocate memory for thread arg.\n");
exit(EXIT_FAILURE);
}
*arg = i;
int rc = pthread_create(&threads[i], NULL, threadfunc, arg);
checkResults("pthread_create()", rc);
}
sleep(3);
printf("Will start to send signals...\n");
while (1) {
printf("***********************************************\n");
for(i=0; i<NUMTHREADS; ++i) {
int rc = pthread_kill(threads[i], SUSPEND_SIG);
checkResults("pthread_kill()", rc);
printf("Waiting for Semaphore for thread %d ...\n", i);
// compute timeout abs timestamp for ack
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
const int TIMEOUT = SUSPEND_DURATION*1000*1000; // in nano-seconds
ts.tv_nsec += TIMEOUT; // timeout to receive ack from signal handler
// normalize timespec
ts.tv_sec += ts.tv_nsec / 1000000000;
ts.tv_nsec %= 1000000000;
rc = sem_timedwait(&sem, &ts); // try decrement semaphore
if (rc == -1 && errno == ETIMEDOUT) {
// timeout
// semaphore is out of sync
printf("Did not received signal handler sem_post before timeout of %d ms for thread %d", TIMEOUT/1000000, i);
abort();
}
checkResults("sem_timedwait", rc);
printf("Received Semaphore for thread %d.\n", i);
}
sleep(1);
}
for(i=0; i<NUMTHREADS; ++i) {
int rc = pthread_join(threads[i], NULL);
checkResults("pthread_join()\n", rc);
}
printf("Main completed\n");
return 0;
}
Questions?
Is it possible for a signal to be dropped and never delivered?
What causes the timeout on the semaphore at random time when the system is loaded?
usleep() is not among the async-signal-safe functions (though sleep() is, and there are other async-signal-safe functions by which you can produce a timed delay). A program that calls usleep() from a signal handler is therefore non-conforming. The specifications do not describe what may happen -- neither with such a call itself nor with the larger program execution in which it occurs. Your questions can be answered only for a conforming program; I do that below.
Is it possible for a signal to be dropped and never delivered?
It depends on what exactly you mean:
If a normal (not real-time) signal is delivered to a thread that already has that signal queued then no additional instance is queued.
A thread can die with signals still queued for it; those signals will not be handled.
A thread can change a given signal's disposition (to SIG_IGN, for example), though this is a per-process attribute, not a per-thread one.
A thread can block a signal indefinitely. A blocked signal is not dropped -- it remains queued for the thread and will eventually be received some time after it is unblocked, if that ever happens.
But no, having successfully queued a signal via the kill() or raise() function, that signal will not be randomly dropped.
What causes the timeout on the semaphore at random time when the system is loaded?
A thread can receive a signal only when it is actually running on a core. On a system with more runnable processes than cores, some runnable processes must be suspended, without a timeslice on any core, at any given time. On a heavily-loaded system, that's the norm. Signals are asynchronous, so you can send one to a thread that is currently waiting for a timeslice without the sender blocking. It is entirely possible, then, that the thread you have signaled does not get scheduled to run before the timeout expires. If it does run, it may have the signal blocked for one reason or another, and not get around to unblocking it before it uses up its timeslice.
Ultimately, you can use your semaphore-based approach to check whether the target thread handled the signal within any timeout of your choice, but you cannot predict in advance how long it will take for the thread to handle the signal, nor even whether it will do so in any finite amount of time (for example, it could die for one reason or another before doing so).
I'm trying to get a pthread example to run on my Windows 10 64-bit machine
I'm compiling using the most recent version of cygwin (64-bit), compiling the code as
gcc thread.c -pthread -o main.exe
which compiles with no error. thread.c looks like so:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
void *worker_thread(void *arg)
{
printf("This is worker_thread()\n");
pthread_exit(NULL);
}
int main()
{
int a = fork();
if (a == 0) {
printf("child a=%d\n", a);
pthread_t my_thread;
int ret = pthread_create(&my_thread, NULL, &worker_thread, NULL);
printf("ret = %d\n", ret);
} else {
printf("parent a=%d\n", a);
int status;
wait(&status);
printf("status = 0x%X (%d)\n", status, status);
}
return 0;
}
On my machine, the output looks like so:
parent a=10868
child a=0
status = 0x7F00 (32512)
which is happening because pthread_create is causing my code to exit.
According to this, this error means:
"It didn't die from a signal, a core dump wasn't produced, and it exited with code 127 (0x7F).
What 127 means is unclear, which is why it should accompanied by an error message."
On my windows 8 64-bit machine, the code runs as expected, with the same build of cygwin (64-bit) installed, and returns this output.
parent a=26744
child a=0
ret = 0
this is worker_thread()
status 0x0 (0)
Any help would be much appreciated.
I'm having trouble handling signals between two process I have running on my computer. scheduler.c is sending the signals and producer.c receiving them. The producer is supposed to print "Printing n" where n is incremented by one each time a SIGUSR1 is received. I have tried using both signal and sigaction to handle the signals but neither is working for me.
scheduler.c:
/*
* scheduler.c
*/
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int n = 1;
int main(int argc, char *argv[])
{
int a = 0; // This variable will be used for the switch later
// Check to ensure correct number of command line arguments
if(argc != 2){
printf("Usage error. Wrong number of arguments\n");
return 1;
}
// Grab PID of producer.c
int producer_pid = atoi(argv[1]);
while(1){
printf("Choose an Option: \n");
printf("1. Request_Production\n");
printf("2. Stop_Producer\n");
printf("3. Stop_Scheduler\n");
scanf("%d", &a);
switch( a )
{
case 1:
kill(producer_pid, 16); //Send SIGUSR1 to producer.c
break;
case 2:
kill(producer_pid, 2); //Send SIGINT to producer.c
break;
// Successfully exit program
case 3:
return 0;
// Invalid Choice
default :
printf("Invalid choice\n");
}
}
}
producer.c:
/*
* producer.c
*/
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int n = 1;
void sigusr1(int signo)
{
printf("Producing %d", n);
n++;
}
int main()
{
struct sigaction act;
sigset_t block_mask;
sigfillset(&block_mask);
act.sa_handler = sigusr1;
act.sa_mask = block_mask;
act.sa_flags = 0;
if(sigaction(SIGUSR1, &act, NULL) == 0){
printf("success");
}
while(1) {
sleep(2);
fflush(stdout);
}
}
This code works for me (on Mac OS X 10.7.5):
producer.c
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static volatile sig_atomic_t n = 0;
static void sigusr1(int signo)
{
n += signo / SIGUSR1;
}
int main(void)
{
struct sigaction act;
sigset_t block_mask;
sigfillset(&block_mask);
act.sa_handler = sigusr1;
act.sa_mask = block_mask;
act.sa_flags = 0;
if (sigaction(SIGUSR1, &act, NULL) == 0)
{
printf("success %d\n", (int)getpid());
while (1)
{
pause();
printf("Producer: %d\n", n);
fflush(stdout);
}
}
}
scheduler.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int a = 0; // This variable will be used for the switch later
// Check to ensure correct number of command line arguments
if (argc != 2)
{
fprintf(stderr, "Usage: %s pid\n", argv[0]);
return 1;
}
// Grab PID of producer.c
int producer_pid = atoi(argv[1]);
while(1)
{
printf("Choose an Option: \n");
printf("1. Request Production\n");
printf("2. Stop Producer\n");
printf("3. Stop Scheduler\n");
scanf("%d", &a);
switch (a)
{
case 1:
if (kill(producer_pid, SIGUSR1) != 0)
fprintf(stderr, "Failed to send signal %d to %d\n", SIGUSR1, producer_pid);
break;
case 2:
if (kill(producer_pid, SIGTERM) != 0)
fprintf(stderr, "Failed to send signal %d to %d\n", SIGTERM, producer_pid);
break;
// Successfully exit program
case 3:
return 0;
// Invalid Choice
default :
fprintf(stderr, "Invalid choice (%d)\n", a);
break;
}
}
}
Sample output
$ (./producer &)
$ success 40119
$ ./scheduler 40119
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 1
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 2
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 3
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 4
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 5
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 6
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 7
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 8
2
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
1
Failed to send signal 30 to 40119
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
3
$
What changed?
Various changes, but the key ones are:
Ensure that output messages end with a newline.
Make n into a volatile sig_atomic_t variable; that's what the C standard says you can access in a signal handler.
Have the main loop in the producer pause() and then print. The pause() system call only returns when interrupted by a signal.
Use symbolic signal names in the scheduler too.
Have the scheduler send SIGTERM rather than SIGINT to terminate the producer. If the producer is run in background, it is ignoring interrupts.
Have the scheduler identify when the kill() calls fail.
Have the producer identify its PID.
I've removed the superfluous headers from the file headings.
The funny signo / SIGUSR1 in the signal handler avoids warnings about unused arguments; it serves no other purpose. As shown, the programs compile cleanly under:
gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition scheduler.c -o scheduler
gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition producer.c -o producer
This is using GCC 4.7.1.
One remark:
There are functions which are safe and others which are not safe to be called from signal handlers.
printf may not be called from a signal handler. write on the other hand is safe.
The list is specified by POSIX-1, but details may vary between operating systems. For Linux, you will find the list in the signal(7):
http://linux.die.net/man/7/signal
I'm trying to implement the times() function in C programming.
I'm using the struct tms structure which consists of the fields: tms_utime, tms_cutime,
tms_stime and tms_cstime.
In order to implement the times() function in my program, I do:
Before I fork and create a child, I call the times function (in the parent process).
times(&start_tms);
I create a pipe and I pass the times of start structure to the pipe when I'm in the child process.
The child executes a simple ls -l command
When the child finishes he execution, the father calls for the second time the times() function.
times(&end_tms);
Unfortunately, the times of end_tms are all zero! Weird, but I don't know why.
Some things I don't understand in my program are:
1) In the first printfs the times of the struct start are negative. Why is that?
2) When I run the program, why do I get zeros for times? What am i doing wrong?
My program is as follows:
Thanks, in advance
#include <sys/times.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main() {
printf("test\n");
int fd[2]; //two pointers
int nbytes;
char string[] = "Hello, world!\n";
char readbuffer[80];
struct tms start_tms;
struct tms end_tms;
clock_t start, end;
double cpu_time_used;
pipe(fd);
//once we have established the pipeline we fork the child
pid_t childpid;
pid_t pid_waitpid;
//NEW MODIFICATION!!! call times before fork()!!!
times(&start_tms);
//they return negative values, but why???
printf("Test start_tms.tms_utime = %f\n\n",start_tms.tms_utime);
printf("Test start_tms.tms_cutime = %f\n\n",start_tms.tms_cutime);
printf("Test start_tms.tms_stime = %f\n\n",start_tms.tms_stime);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
/* call times function */
/*times(&start_tms);*/
//REMOVED!!!!
//write(fd[1], string, (strlen(string)+1));
write(fd[1], &start_tms.tms_cutime, sizeof(clock_t));
write(fd[1], &start_tms.tms_utime, sizeof(clock_t));
write(fd[1], &start_tms.tms_stime, sizeof(clock_t));
//execute /bin/ls
execl("/bin/ls", "/bin/ls", "-r", "-t", "-l", (char *) 0);
exit(0);
}
else
{
/* Parent process closes up output side of pipe */
close(fd[1]);
/* NEW MODIFICATION, wait for the child!!! */
if( (pid_waitpid = waitpid(childpid,NULL,0) ) == -1)
{
perror("waitpid");
exit(1);
}
/* call times for capturing end times */
times(&end_tms);
/* define t1, t2, variables */
clock_t t1,t2,t3;
//REMOVED!!!!
//nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
read(fd[0], &t1, sizeof(clock_t));
read(fd[0], &t2, sizeof(clock_t));
read(fd[0], &t3, sizeof(clock_t));
printf("Received string: %s\n\n", readbuffer);
printf("Test t1 = %f\n\n",t1);
printf("Test end_tms.tms_utime = %f\n\n",end_tms.tms_utime);
printf("Test end_tms.tms_cutime = %f\n\n",end_tms.tms_cutime);
printf("Test end_tms.tms_stime = %f\n\n",end_tms.tms_stime);
/* Calculate times, unfortunately return zero, but why??? */
double cpu_time = end_tms.tms_cutime - t1;
double utime = end_tms.tms_utime - t2;
double stime = end_tms.tms_stime - t3;
//Unfortunately printfs return zero, but why???
printf("cpu time %f\n\n",cpu_time);
printf("cpu Utime %f\n\n",utime);
printf("cpu Stime %f\n\n",stime);
}
}
Your logic is very strange. The writes you do in the child simply copy data that is already available to the parent in start_tms, so your whole pipe read/write thing is unnecessary.
Secondly, clock_t is not a floating point type, it's an integral type. You can't use %f to print it. Use %jd and intmax_t to be safe in the printfs.
And you're missing #include <sys/wait.h> for waitpid. So turn on your compiler warnings, and read them.
Here's a C99 version of your code that works here:
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/wait.h>
#include <sys/times.h>
#include <sys/types.h>
int main() {
struct tms start_tms;
struct tms end_tms;
//once we have established the pipeline we fork the child
pid_t childpid;
times(&start_tms);
printf("Test start_tms.tms_utime = %jd\n\n", (intmax_t)start_tms.tms_utime);
printf("Test start_tms.tms_cutime = %jd\n\n", (intmax_t)start_tms.tms_cutime);
printf("Test start_tms.tms_stime = %jd\n\n", (intmax_t)start_tms.tms_stime);
printf("Test start_tms.tms_cstime = %jd\n\n", (intmax_t)start_tms.tms_cstime);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
//execute /bin/ls
execl("/bin/ls", "/bin/ls", "-R", "-t", "-l", (char *) 0);
exit(0);
}
else
{
/* Parent process */
/* NEW MODIFICATION, wait for the child!!! */
if (waitpid(childpid,NULL,0) == -1)
{
perror("waitpid");
exit(1);
}
/* call times for capturing end times */
times(&end_tms);
printf("Test end_tms.tms_utime = %jd\n\n",end_tms.tms_utime);
printf("Test end_tms.tms_cutime = %jd\n\n",end_tms.tms_cutime);
printf("Test end_tms.tms_stime = %jd\n\n",end_tms.tms_stime);
printf("Test end_tms.tms_cstime = %jd\n\n",end_tms.tms_cstime);
/* Calculate times, unfortunately return zero, but why??? */
clock_t cpu_time = end_tms.tms_cutime - start_tms.tms_cutime;
clock_t utime = end_tms.tms_utime - start_tms.tms_utime;
clock_t stime = end_tms.tms_stime - start_tms.tms_stime;
clock_t cstime = end_tms.tms_cstime - start_tms.tms_cstime;
//Unfortunately printfs return zero, but why???
printf("cpu time %jd\n\n", (intmax_t)cpu_time);
printf("cpu Utime %jd\n\n", (intmax_t)utime);
printf("cpu Stime %jd\n\n", (intmax_t)stime);
printf("cpu CStime %jd\n\n", (intmax_t)cstime);
}
}
If you don't have intmax_t, check the size of clock_t on your implementation and find a standard integer type that matches it, and use the appropriate format string in your printf calls.