I am beginner in C language. I have a question and the question is only about my curiosity. I have done a task recently. The fallowing code calculates time of process between parent and child. I am taking command
like ls,pwd etc. via input. As a sample, while the code calculates time of -ls command, it does not calculate ls -l. I know I need to change execlp but I do not know which one is better according to that exec family ? In other words, How can I integrate true exec() family type to my code ? Could you help me ?
My example output for ls :
ls
a.out main.c
2006152 ms
My output for ls -l:
ls -l
Error exec: No such file or directory
My codes :
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#define N 20
void ChildProcess();
void ParentProcess();
struct timeval start, end;
char *input;
int main (int argc,char **argv) {
input = argv[1];
pid_t pid;
pid = fork();
if (pid == 0){
ChildProcess ();
}
else {
wait (NULL);
ParentProcess ();
}
return 0;
}
void ChildProcess () {
/* the size (in bytes) of shared memory object */
const int SIZE = 4096;
/* name of the shared memory object */
const char* name = "OS";
/* shared memory file descriptor */
int shm_fd;
/* pointer to shared memory obect */
long int* ptr;
/* create the shared memory object */
shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
/* configure the size of the shared memory object */
ftruncate(shm_fd, SIZE);
/* memory map the shared memory object */
ptr =(long int*)mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
gettimeofday(&start, NULL);
printf("%ld ",start.tv_usec);
*ptr=start.tv_usec;
if (execlp (input, "", (char *) 0) < 0)
{
perror ("Error exec");
exit (0);}
}
}
void ParentProcess () {
/* the size (in bytes) of shared memory object */
const int SIZE = 4096;
/* name of the shared memory object */
const char* name = "OS";
/* shared memory file descriptor */
int shm_fd;
/* pointer to shared memory object */
long int* ptr;
/* open the shared memory object */
shm_fd = shm_open(name, O_RDONLY, 0666);
/* memory map the shared memory object */
ptr =(long int*)mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
/* read from the shared memory object */
printf("%ld usec okunan\n ", *ptr);
long int start_usec = *ptr;
/* remove the shared memory object */
shm_unlink(name);
gettimeofday(&end,NULL);
printf("%ld son : ",end.tv_usec);
printf ("Total time : %ld %s dir \n", end.tv_usec-start_usec, "ms");
}
You are responsible for writing code to split up the input string up into separate arguments that you can pass to execvp:
/* Take your string "ls -l" and split it up into an array like this: */
char* split[3];
split[0] = "ls";
split[1] = "-l";
split[2] = NULL;
execvp(split[0], split);
If you don't know how to split strings in C to make this happen, you will have to research and learn that separately.
Alternatively, you can ask a shell to do it for you. However, this will also measure the startup and processing time of the shell:
char* command = "ls -l";
execlp("sh", "sh", "-c", command, NULL);
Related
In the child process the mapping is giving me issue. the parent is creating a shared memory and child is using it for writing a message to parent but when the mmap executes, it gives an error of permission denied. kindly help me to get rid of this issue. everything else is running file. when I try to create shared memory in child process the issue is resolved but the requirement is creating shared memory in parent process, that is why it is taking time to solve it.
/**
* Simple program demonstrating shared memory in POSIX systems.
*
* This is the consumer process
*
* Figure 3.18
*
* To compile, enter
* gcc shm-posix-consumer.c -lrt
*
* #author Gagne, Galvin, Silberschatz
* Operating System Concepts - Tenth Edition
* Copyright John Wiley & Sons - 2018
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mman.h>
int main()
{
const int SIZE = 4096;
const char *name = "OS";
//shm_unlink(name);
int shm_fd;
void *ptr;
pid_t pid;
pid=fork();
if(pid==-1) {
printf("Error in creating a child process\n");
return -1;
}
else if(pid==0) {
sleep(2);
printf("child process is executing\n");
/* open the shared memory segment */
shm_fd = shm_open(name, O_RDWR, S_IRWXU);
if (shm_fd == -1) {
printf("opening of shared memory failed\n");
exit(-1);
}
if(ftruncate(shm_fd,SIZE)==-1){
printf("Error in configuring the size of shared memory");
exit(1);
}
/* now map the shared memory segment in the address space of the process */
ptr = mmap(0,SIZE,PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED) {
perror("Map failed in child process\n");
printf("error:%s %d",strerror(errno),errno);
return -1;
}
char *message0;
strcpy(message0,"Greeting to parent");
printf("Message to parent from child:%s\n",message0);
sprintf(ptr,"%s",message0);
ptr += strlen(message0);
if(munmap(ptr,SIZE)==-1){
printf("munmap error:\n");
exit(1);
}
close(shm_fd);
}
else {
printf("parent process is executing\n");
/* create the shared memory segment */
shm_fd = shm_open(name, O_CREAT | O_RDWR, S_IRWXU);
/* configure the size of the shared memory segment */
if(ftruncate(shm_fd,SIZE)==-1){
printf("Error in configuring the size of shared memory");
exit(1);
}
printf("parent process wait after creating shared memory\n");
wait(NULL);
printf("back to parent process after child termination\n");
/* now map the shared memory segment in the address space of the process */
ptr = mmap(0,SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED) {
printf("Map failed in parent\n");
return -1;
}
printf("%s\n",(char *)ptr);
if (shm_unlink(name) == -1) {
printf("Error removing %s\n",name);
exit(-1);
}
}
return 0;
}
At least three problems:
char *message0;
strcpy(message0,"Greeting to parent");
You are using message0 uninitialized, switch to something like
char message0[64];
strcpy(message0,"Greeting to parent");
or simply:
char *message0 = "Greeting to parent";
Here:
void *ptr;
...
ptr += strlen(message0);
You can't use pointer arithmetic with void *, switch to char *ptr;
And here:
ptr += strlen(message0);
if(munmap(ptr,SIZE)==-1){
you need to rewind ptr to the original position returned by mmap before calling munmap, it seems that you can remove this line:
ptr += strlen(message0);
Now it works for me adding #define _XOPEN_SOURCE 500 at the very beginning (for ftruncate).
I have a code. There are 2 processes. Parent is writer on file a.txt. Child is reader on a.txt.Parent has 2 threads and child has 2 threads. Parent's 1st thread opens a file parent1.txt . reads 128 chars. writes to a.txt.Parent's 2nd thread opens file parent2.txt.reads 128 chars. writes to a.txt. Child's 1st thread reads 128 chars from a.txt and writes to child1.txt. child's 2nd thread reads 128 chars from a.txt and child2.txt. Any parent thread , after writing, should generate event and invoke the child's reader threads.I have implemented a solution using mutex and condition variable.Parent's writer threads generate pthread_cond_signal after writing to a.txt. 1>But child's reader threads are not running after that. both parent threads are running in loop.2>Parent reads frm parent1.txt. the fread is successfull. But when it writes to a.txt, it is not successfull. the a.txt file is always empty.I think mutex can not be use between multiple processes. That may be 1 problem
My code is as follows
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
FILE*fd,*fdRead1,*fdRead2,*fdWrite1,*fdWrite2;
pthread_mutex_t *mut1;
pthread_mutexattr_t attrmutex;
pthread_cond_t *cond_var;
pthread_condattr_t attrcond;
#define OKTOWRITE "/condwrite"
#define MESSAGE "/msg"
#define MUTEX "/mutex_lock"
void* R1(void *)
{
char buf[128];
int size;
fdWrite1 = fopen("child1.txt","w+");
cout<<"R1Thread"<<endl;
for(int i=0;i<10;i++)
{
cout<<"R1Thread-1"<<endl;
pthread_mutex_lock(mut1);
pthread_cond_wait(cond_var,mut1);
cout<<"R1Thread-2"<<endl;
size = fread(buf,128,1,fd);
fwrite(buf,size,1,fdWrite1);
pthread_mutex_unlock(mut1);
}
fclose(fdWrite1);
}
void* R2(void *)
{
char buf[128];
int size;
fdWrite2 = fopen("child2.txt","w+");
cout<<"R2Thread"<<endl;
for(int i=0;i<10;i++)
{
cout<<"R2Thread-1"<<endl;
pthread_mutex_lock(mut1);
pthread_cond_wait(cond_var,mut1);
cout<<"R2Thread-2"<<endl;
size = fread(buf,128,1,fd);
fwrite(buf,size,1,fdWrite2);
pthread_mutex_unlock(mut1);
}
fclose(fdWrite2);
}
void* W1(void *)
{
char buf[128];
int size;
fdRead1 = fopen("parent1.txt","r");
for(int i=0;i<10;i++)
{
pthread_mutex_lock(mut1);
size = fread(buf,128,1,fdRead1);
fwrite(buf,size,1,fd);
pthread_cond_signal(cond_var);
cout<<"W2Thread-1"<<endl;
pthread_mutex_unlock(mut1);
sleep(10);
}
fclose(fdRead1);
}
void* W2(void *)
{
char buf[128];
int size;
fdRead2 = fopen("parent2.txt","r");
for(int i=0;i<10;i++)
{
pthread_mutex_lock(mut1);
size = fread(buf,128,1,fdRead2);
fwrite(buf,size,1,fd);
pthread_cond_signal(cond_var);
cout<<"W2Thread-1"<<endl;
pthread_mutex_unlock(mut1);
sleep(1000);
}
fclose(fdRead2);
}
int main()
{
int des_cond, des_msg, des_mutex;
int mode = S_IRWXU | S_IRWXG;
des_mutex = shm_open(MUTEX, O_CREAT | O_RDWR | O_TRUNC, mode);
if (des_mutex < 0) {
perror("failure on shm_open on des_mutex");
exit(1);
}
if (ftruncate(des_mutex, sizeof(pthread_mutex_t)) == -1) {
perror("Error on ftruncate to sizeof pthread_cond_t\n");
exit(-1);
}
mut1 = (pthread_mutex_t*) mmap(NULL, sizeof(pthread_mutex_t),
PROT_READ | PROT_WRITE, MAP_SHARED, des_mutex, 0);
if (mut1 == MAP_FAILED ) {
perror("Error on mmap on mutex\n");
exit(1);
}
des_cond = shm_open(OKTOWRITE, O_CREAT | O_RDWR | O_TRUNC, mode);
if (des_cond < 0) {
perror("failure on shm_open on des_cond");
exit(1);
}
if (ftruncate(des_cond, sizeof(pthread_cond_t)) == -1) {
perror("Error on ftruncate to sizeof pthread_cond_t\n");
exit(-1);
}
cond_var = (pthread_cond_t*) mmap(NULL, sizeof(pthread_cond_t),
PROT_READ | PROT_WRITE, MAP_SHARED, des_cond, 0);
if (cond_var == MAP_FAILED ) {
perror("Error on mmap on condition\n");
exit(1);
}
/* Initialise attribute to mutex. */
pthread_mutexattr_init(&attrmutex);
pthread_mutexattr_setpshared(&attrmutex, PTHREAD_PROCESS_SHARED);
/* Allocate memory to pmutex here. */
/* Initialise mutex. */
pthread_mutex_init(mut1, &attrmutex);
/* Initialise attribute to condition. */
pthread_condattr_init(&attrcond);
pthread_condattr_setpshared(&attrcond, PTHREAD_PROCESS_SHARED);
/* Allocate memory to pcond here. */
/* Initialise condition. */
pthread_cond_init(cond_var, &attrcond);
pthread_t thR1,thR2,thW1,thW2;
fd = fopen("a.txt","w+");
int res = fork();
if(res<0) perror("error forking\n");
if(res==0)//child
{
cout<<"child created"<<endl;
pthread_create(&thR1,0,R1,0);
//pthread_create(&thR2,0,R2,0);
pthread_join(thR1,0);
//pthread_join(thR2,0);
fclose(fd);
}
else//parent
{
//fdRead = fopen("parent.txt","r");
pthread_create(&thW1,0,W1,0);
//pthread_create(&thW2,0,W2,0);
pthread_join(thW1,0);
//pthread_join(thW2,0);
fclose(fd);
wait(0);
}
}
The output is as follows-
child created
W2Thread-1
R1Thread
R1Thread-1
W2Thread-1
W2Thread-1
W2Thread-1
W2Thread-1
W2Thread-1
W2Thread-1
W2Thread-1
W2Thread-1
The condition_wait in child never comes out.
There are potential issues with using multiple processes, each with multiple threads, but they mostly revolve around program state at the time of the fork. Since your program forks before it creates any additional threads, you can be confident about its state at that time, and in particular, you can be confident that its one thread is not at that time executing in a critical section. This is fine.
However, you are missing two key details:
Although you set the mutex to be process-shared, the version of the code you initially presented failed to do the same for the condition variable.
Setting pthread_* synchronization objects to be process-shared is necessary, but not sufficient, for inter-process use. For that, you need the synchronization objects to reside in shared memory accessed by all participating processes. Only that way can all the process access the same objects.
The goal of this code is to create a shared memory space and write n's value to it in the child then print all the numbers generated in from the parent process. But this presently just prints out memory addresses like 16481443B4 which change every time I run the program. I am not sure if I am writing to the shared memory incorrectly or reading from the shared memory incorrectly. Possibly both.
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include <sys/mman.h>
int main(int argc, char** argv){
//shared memory file descriptor
int shm_fd;
//pointer to shared memory obj
void *ptr;
//name of shared obj space
const char* name = "COLLATZ";
//size of the space
const int SIZE = 4096;
//create a shared memory obj
shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
//config size
ftruncate(shm_fd, SIZE);
//memory map the shared memory obj
ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
int n = atoi(argv[1]);
pid_t id = fork();
if(id == 0) {
while(n>1) {
sprintf(ptr, "%d",n);
ptr += sizeof(n);
if (n % 2 == 0) {
n = n/2;
} else {
n = 3 * n + 1;
}
}
sprintf(ptr,"%d",n);
ptr += sizeof(n);
} else {
wait(NULL);
printf("%d\n",(int*)ptr);
}
//Umap the obj
munmap(ptr, SIZE);
//close shared memory space
close(shm_fd);
return 0;
}
Listen to your compiler!
$ gcc main.c -lrt
main.c: In function 'main':
main.c:51:9: warning: format '%d' expects argument of type 'int', but argument 2 has type 'int *' [-Wformat=]
printf("%d\n",(int*)ptr);
^
Assuming you want to print the integer pointed to by ptr, it should be:
printf("%d\n",*((int*)ptr));
I was trying to figure out shared memory and tried to write a simple program involving a consumer and a producer. I didnt make it to the consumer part and found this weird little problem: The parent will return at the *spool=3; with no rhyme or reason on why. Nothing on dmesg.
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define PRODUCER_ERROR(msg) \
do {perror("Producer Error: " msg "\n"); exit(1); }while(0)
#define SHM_NAME "/my_sharedmem"
void producer();
int main(int argc, char *argv[])
{
pid_t pID = fork();
if (pID == 0) {
// Code only executed by child process
printf ("Son here\n");
return 0;
} else if (pID < 0) {
perror("Unable to fork\n");
exit(1);
} else {
// Code only executed by parent process
printf ("Parent here\n");
producer();
return 0;
}
return 0;
}
void producer()
{
int fd, d;
unsigned* spool;
printf("<<Producer>> started\n");
fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO ); // FIXED
printf ("<<Producer>> memory file opened\n");
spool = mmap(NULL, sizeof(unsigned), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0);
printf ("<<Producer>> mmaped to %p\n\tGonna write.\n", spool);
perror(NULL);
*spool = 3;
// msync(spool, sizeof(unsigned), MS_SYNC | MS_INVALIDATE);
printf("<<Producer>> ended\n");
}
EDIT: fixed shm_open mode argument
The object you get with shm_open is zero size. You need to allocate some space for it. mmap will allow you to map things beyond their size (both shm objects and files), but you'll crash when you access that memory.
Something like this after shm_open is what you want to do:
ftruncate(fd, <the size you want>);
You can do it after mmap too, if that floats your boat.
You have the mode argument to shm_open wrong. This is supposed to be a mode specification as for open. Probably your version here by conincidence forbids writing to the address, so the process then crashes when you try to write to it.
BTW: you should always check the return of library calls such as shm_open and mmap.
Edit: As I also observed in a comment below, you are also missing to scale the segment to an appropriate size with ftruncate.
I create a shared memory in program A with the following codes:
shm = shm_open("/mfs_hash_pool_container", O_CREAT|O_RDWR, 0666);
size = sizeof(struct mfs_hash_pool_container);
ftruncate(shm, size);
mfs_hash_pool_stat_p = (struct mfs_hash_pool_container *)mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shm, 0);
I use that to store a hash table.
The other program B, will receives the addr (mfs_hash_pool_stat_p+offset) send from program A, but I can not write it in B.
Does this means I must also open this shared memory in B? Is there any other way to solve that? Because I create this memory automatically.
Thanks you guys.
You can't just use that address in the other program. B has to:
Obtain the file descriptor: shm_open("/mfs_hash_pool_container", O_RDWR, 0)
Map memory for the file descriptor: mmap just like A does
Notes:
You need to check the return value of mmap (it could return MAP_FAILED)
You need not cast the return value of mmap
Separate processes do not share memory, so the address being passed to B from A will not point to the shared memory segment. Each process must call shm_open() and mmap() the segment individually.
If you have information about the segment that every process needs to be aware of, pack it at the beginning of the segment in an order that each process is aware of.
I am not sure about how your program A and program B are related, but if you manage to spawn 'B' from 'A', using fork() + execve() combination, then you need not worry about passing the memory pointer as both processes will have the same copy.
For your reference I am pasting a nice code example present at IBM developerworks here-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/wait.h>
void error_and_die(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
int r;
const char *memname = "sample";
const size_t region_size = sysconf(_SC_PAGE_SIZE);
int fd = shm_open(memname, O_CREAT | O_TRUNC | O_RDWR, 0666);
if (fd == -1)
error_and_die("shm_open");
r = ftruncate(fd, region_size);
if (r != 0)
error_and_die("ftruncate");
void *ptr = mmap(0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
error_and_die("mmap");
close(fd);
pid_t pid = fork();
if (pid == 0)
{
u_long *d = (u_long *)ptr;
*d = 0xdbeebee;
exit(0);
}
else
{
int status;
waitpid(pid, &status, 0);
printf("child wrote %#lx\n", *(u_long *)ptr);
}
r = munmap(ptr, region_size);
if (r != 0)
error_and_die("munmap");
r = shm_unlink(memname);
if (r != 0)
error_and_die("shm_unlink");
return 0;
}
Read the full article in the above link to gain a better understanding of shared memory!
Process do not share memory by default. If you want this 2 processes to communicate or share memory, you'll have to make that happen. Check this question.
Another solution is to use threads, which share code and memory alike.