The GNU's clone() function got stuck - c

I am writing a program using Code::Blocks 16.01 in CentOS 7.3. The program is contains the main function and a child process (or so-called thread) created by the clone() function. My purpose is to test whether the chdir() function affects the working directory in the main function by removing the CLONE_FS parameter. Hopefully it works, but new problem occurs. Please read my code first:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sched.h>
#include <fcntl.h>
#define STACK_SIZE 1024*1024*8
int thread_func(void *arg){
int i;
char *cdir;
for(i = 0; i < 100; i++){
switch(i%3){
case 0:
chdir("/home/centos/dirtest/dir000");
break;
case 1:
chdir("/home/centos/dirtest/dir001");
break;
case 2:
chdir("/home/centos/dirtest/dir002");
break;
}
cdir = getcwd(NULL,0);
fprintf(stderr,"Child Thread in # %d: %s\n",i,cdir);
}
free(cdir);
return 1;
}
int main(){
void *pstack = (void*)mmap(NULL, STACK_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_ANON,
-1, 0);
if(MAP_FAILED != pstack){
int ret,i;
char *cdir;
ret = clone(thread_func,
(void*)((unsigned char *)pstack + STACK_SIZE),
CLONE_VM | CLONE_FILES ,
NULL);
if(ret == -1){
fprintf(stderr,"Thread create failed\n");
return 0;
}
for(i = 0; i < 100; i++){
cdir = getcwd(NULL,0);
fprintf(stderr,"Main Function in # %d: %s\n",i,cdir);
}
free(cdir);
}
return 1;
}
However, when I run the generated exe file in the terminal by command line, it got stuck. Neither the main function nor the child process could finish its "for" loop, and I had to terminate the program by "Ctrl-C".
Could anybody find the problem ?
********Here are edits of new progress********
Thanks for the comments, I've made changes on the getcwd() function. Also I added the waitpid() function. However, it shows failure. The modified code is as follows:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sched.h>
#include <fcntl.h>
#define STACK_SIZE 1024*1024*8
int thread_func(void *arg){
int i;
char cdir[1024];
for(i = 0; i < 100; i++){
switch(i%3){
case 0:
chdir("/home/centos/dirtest/dir000");
break;
case 1:
chdir("/home/centos/dirtest/dir001");
break;
case 2:
chdir("/home/centos/dirtest/dir002");
break;
}
getcwd(cdir,sizeof(cdir));
fprintf(stderr,"Child Thread in # %d: %s\n",i,cdir);
}
return 1;
}
int main(){
/*void *pstack = (void*)mmap(NULL, STACK_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS ,
-1, 0);
if(MAP_FAILED != pstack){*/
void *pstack = malloc(STACK_SIZE);
int ret,i;
char cdir[1024];
ret = clone(thread_func,
(void*)((char *)pstack + STACK_SIZE),
CLONE_VM | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD,
NULL);
if(ret == -1){
fprintf(stderr,"Thread create failed\n");
goto mem;
}
for(i = 0; i < 100; i++){
getcwd(cdir,sizeof(cdir));
fprintf(stderr,"Main Function in # %d: %s\n",i,cdir);
}
ret = waitpid(ret,0,0);
if(ret == -1){
fprintf(stderr,"waitpid failed\n");
}
mem:
//}
free(pstack);
return 1;
}

I'm quite certain that one of the problems is that you have multiple threads of execution touching libc without actually preparing libc for it. When threads are spawned normally, with pthreads, they run some code that prepares libc for multiple threads touching stdio (you print to stderr), enable locking for malloc (since you do mallocs inside getcwd), set up TLS and generally make sure that things don't run into each other.
You've done none of that. You're of course free to spawn your own threads with clone manually, but then it's your responsibility to make sure that all the code you call is thread safe. You can't just call into libc and hope for the best, that won't work. Libc expects that either there is just one thread executing or that the threads were created with pthreads.

Related

sem_unlink(): permission denied on macOS

I am working on a school assignment using semaphores, every time I restart my mechine everything works as expected but after running my code, the second try gives undefined results. I've come to a conclusion that my machine don't give me permission to unlink any created semaphores, and checking the errno showed that my conclusion was correct. It gives errno EACCES, how can I fix this problem? I am working on the last visions of Xcode (12.2).
The code I am running:
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h> /* For O_* constants */
#include <errno.h>
const char *semName1 = "my_sema1";
const char *semName2 = "my_sema2";
int main(int argc, char **argv)
{
pid_t pid;
sem_t *sem_id1 = sem_open(semName1, O_CREAT, O_RDWR, 1);
sem_t *sem_id2 = sem_open(semName2, O_CREAT, O_RDWR, 0);
int i, status;
pid = fork();
if (pid) {
for (i = 0; i < 100; i++) {
sem_wait(sem_id1);
putchar('A'); fflush(stdout);
sem_post(sem_id2);
}
sem_close(sem_id1);
sem_close(sem_id2);
wait(&status);
int error = sem_unlink(semName1);
int hej2 = sem_unlink(semName2);
printf("%d \n",error);
if (errno == EACCES){
printf("%d \n",error);
}
} else {
for (i = 0; i < 100; i++) {
sem_wait(sem_id2);
putchar('B'); fflush(stdout);
sem_post(sem_id1);
}
sem_close(sem_id1);
sem_close(sem_id2);
}
}
Appreciate your help
Quick Answer: Run the program as root
Long Answer:
Given this code snippet:
#include <errno.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
sem_t *sem_id1 = sem_open("sem_id1", O_CREAT, O_RDWR, 0);
if (sem_id1 == SEM_FAILED)
{
perror("sem_open");
exit(1);
}
printf("sem_open: Successful\n");
int rc = sem_unlink("sem_id1");
if (rc != 0)
{
perror("sem_unlink");
exit(1);
}
printf("sem_unlink: Successful\n");
return 0;
}
The first time it's run, it will let you create the semaphore, but fail to unlink it:
./main
sem_open: Successful
sem_unlink: Permission denied
The second time it will fail even to create the semaphore:
./main
sem_open: Permission denied
The issue is clearly with permissions, and running the program as root fixes it:
sudo ./main
sem_open: Successful
sem_unlink: Successful
Why does it need root privileges?
Quoting from the man page:
POSIX semaphores come in two forms: named semaphores and unnamed semaphores.
...
Persistence
POSIX named semaphores have kernel persistence: if not removed by sem_unlink(3), a semaphore will exist until the system is shut down.
These are named semaphores.
The fn sem_open and sem_unlink are possibly affecting processes that don't belong to you: imagine if you could run a program that overwrites or removes another process' semaphore without root permissions!

Understanding the code in C involving processes

Someone can explain me why the first code the variable "v" dont change the value in the last prinft() and se second code the variable "v" change.
First code:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int v = 5;
int main(){
pid_t piid;
piid = fork();
if(piid==0){
v += 15;
return 0;
}
else if(piid >0){
wait(NULL);
printf("Final value = %d\n",v);
return 0;
}
}
I know this code be involving fork() for create another process maybe
Second code:
#define _GNU_SOURCE
#include <stdlib.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <sched.h>
#include <stdio.h>
// 64kB stack
#define FIBER_STACK 1024*64
int v = 5;
int threadFunction( void* argument )
{
v += 10;
return 0;
}
int main(){
void* stack;
pid_t pid;
stack = malloc( FIBER_STACK );
if ( stack == 0 )
{
perror("malloc: could not allocate stack\n");
exit(1);
}
pid = clone( &threadFunction, (char*) stack + FIBER_STACK,
SIGCHLD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM, 0 );
if ( pid == -1 )
{
perror( "clone" );
exit(2);
}
pid = waitpid( pid, 0, 0 );
if ( pid == -1 )
{
perror( "waitpid" );
exit(3);
}
free( stack );
printf("Final value = %d\n", v);
return 0;
}
This code is a thread, but I can not understand the so-called clone () and what's inside there.
Forking a new process creates a standalone and distinct copy of the original process. Changing something in the process copy will not change anything in the original process.
Threads are different, they share everything. All threads are still parts of the same process.
While the clone system call can create a new process (that's what happens when you call fork in Linux actually) it can also be used to create a thread, which is what happens in the second program.
threads run in a shared memory space, while processes run in separate memory spaces.
so in the first case using fork each process has different reference of the variable v while in the thread both has the same reference.

Segmentation fault when using semaphores with POSIX shared memory

I have a problem with some simple code I'm writing to teach myself about semaphores and POSIX shared memory.
The idea is that one program, the server, opens the shared memory and writes a structure (containing a semaphore and an array) to it. Then it waits for input and after input increments the semaphore.
Meanwhile the client opens the shared memory, waits on the semaphore, and after it is incremented by the server, reads the structure.
The server seems to work okay, however I am encountering a segfault in the client at the sem_wait function, immediately (even before the server increments it). I can't figure out what is wrong.
Server code:
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <semaphore.h>
#include <stdbool.h>
#define ARRAY_MAX 1024
typedef struct {
sem_t inDataReady;
float array[ARRAY_MAX];
unsigned arrayLen;
} OsInputData;
int main() {
int shm_fd;
OsInputData *shm_ptr;
if((shm_fd = shm_open("/my_shm", O_CREAT | O_RDWR, 0666)) == -1) {
printf("shm_open failure\n");
return 1;
}
if(ftruncate(shm_fd, sizeof(OsInputData)) == -1) {
printf("ftruncate failure\n");
return 1;
}
if((shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
printf("mmap failure\n");
return 1;
}
sem_init(&(shm_ptr->inDataReady), true, 0);
shm_ptr->array[0] = 3.0;
shm_ptr->array[1] = 1.0;
shm_ptr->array[2] = 2.0;
shm_ptr->array[3] = 5.0;
shm_ptr->array[4] = 4.0;
shm_ptr->arrayLen = 5;
getchar();
sem_post(&(shm_ptr->inDataReady));
sem_destroy(&(shm_ptr->inDataReady));
munmap(shm_ptr, sizeof(OsInputData));
close(shm_fd);
return 0;
}
Client code:
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <semaphore.h>
#include <stdbool.h>
#define ARRAY_MAX 1024
typedef struct {
sem_t inDataReady;
float array[ARRAY_MAX];
unsigned arrayLen;
} OsInputData;
int main() {
int shm_fd;
OsInputData *shm_ptr;
if((shm_fd = shm_open("/my_shm", O_RDONLY, 0666)) == -1) {
printf("shm_open failure\n");
return 1;
}
if((shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
printf("mmap failure\n");
return 1;
}
sem_wait(&(shm_ptr->inDataReady));
printf("%u\n", shm_ptr->arrayLen);
munmap(shm_ptr, sizeof(OsInputData));
close(shm_fd);
return 0;
}
The actual outcome depends upon your system, but in general your program contains an error. You can’t destroy a semaphore that is reachable by another process/thread. Just because you have executed a sem_post doesn’t mean that your system has switched to the process waiting for it. When you destroy it, the other guy might still be using it.
SIGSEGV, in this case, is a kindness. Few programmers check the return values of sem_wait, which can lead to programs thinking they are synchronized when they are not.
Turns out I had to open the shared memory in the client with both read and write permissions, as well as update the protections accordingly in mmap.
Quite a stupid mistake, as it's obvious the client needs write permissions as well to actually modify the semaphore.
So in the client code the following changes solved it
...
shm_fd = shm_open("/my_shm", O_CREAT | O_RDWR, 0755)
...
shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0)
...

Reading and writng with named pipes C

I'm writing a program that should run indefinitely maintaining the value of a variable. Two other programs could change the value of the variable. I use named pipes to receive and send the variable value to external programs.
Here is my code for the manager of the variable.
manager.c:
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
char a = 'a';
void *editTask(void *dummy)
{
int fd;
char* editor = "editor";
mkfifo(editor, 0666);
while(1)
{
fd = open(editor, O_RDONLY);
read(fd, &a, 1);
close(fd);
}
}
void *readTask(void *dummy)
{
int fd;
char* reader = "reader";
mkfifo(reader, 0666);
while(1)
{
fd = open(reader, O_WRONLY);
write(fd,&a,1);
close(fd);
}
}
int main()
{
pthread_t editor_thread, reader_thread;
pthread_create(&editor_thread, NULL, editTask, NULL);
pthread_create(&reader_thread, NULL, readTask, NULL);
pthread_join (editor_thread, NULL);
pthread_join (reader_thread, NULL);
return 0;
}
This program uses pthreads to separately get external values for the variable and to communicate the current value of the variable to external programs.
The program that is able to write values to the variable is:
writer.c:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char** argv)
{
if(argc != 2)
{
printf("Need an argument!\n");
return 0;
}
int fd;
char * myfifo = "editor";
fd = open(myfifo, O_WRONLY);
write(fd, argv[0], 1);
close(fd);
return 0;
}
The program that could read the current value is:
reader.c:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
int fd;
char * myfifo = "reader";
fd = open(myfifo, O_RDONLY);
char value = 'z';
read(fd, &value, 1);
printf("The current value of the variable is:%c\n",value);
close(fd);
return 0;
}
I ran these programs in my Ubuntu system as follows:
$ ./manager &
[1] 5226
$ ./writer k
$ ./reader
bash: ./reader: Text file busy
Why doesn't my system allow me to run this program?
Thank you.
You are trying to call both the FIFO and the reader program "reader".
Also, you have no error checking. You have no idea whether those calls to mkfifo and open succeeded or not. Adding this is critical before you attempt to do any troubleshooting.

IPC FIFO Producer-Consumer Deadlock

This is the producer.
// speak.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define FIFO_NAME "american_maid"
int main(void)
{
char s[300];
int num, fd;
mknod(FIFO_NAME, S_IFIFO | 0666, 0);
printf("waiting for readers...\n");
fd = open(FIFO_NAME, O_WRONLY);
printf("got a reader--type some stuff\n");
while (gets(s), !feof(stdin)) {
if ((num = write(fd, s, strlen(s))) == -1)
perror("write");
else
printf("speak: wrote %d bytes\n", num);
}
return 0;
}
And this is the consumer.
//tick.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define FIFO_NAME "american_maid"
int main(void)
{
char s[300];
int num, fd;
mknod(FIFO_NAME, S_IFIFO | 0666, 0);
printf("waiting for writers...\n");
fd = open(FIFO_NAME, O_RDONLY);
printf("got a writer\n");
do {
if ((num = read(fd, s, 300)) == -1)
perror("read");
else {
s[num] = '\0';
printf("tick: read %d bytes: \"%s\"\n", num, s);
}
} while (num > 0);
return 0;
}
When I run them, Producer outputs,
waiting for readers...
And consumer outputs,
waiting for writers...
speak doesn't find the reader, tick. As from the theory here I got that, open() (speak.c) will be keep blocked until open() (tick.c) is opened. And the vice versa. So I guess there a deadlock or something happening. I need a solution of this.
It looks like you have a race condition between the reader and the writer.
To fix this, you need a method of not launching the reader until the writer is "active". For this, I'd suggest making a pipe and writing to it when the writer is ready. Then, when reading from the read end of the fork succeeds, the fifo is prepared and the reader should work.
You need to use forks here because coordinating mutexes between a parent and a child process is non-trivial and properly done pipes is easier.
Also, you called mknod() twice. Granted, it'll return -1 with errno == EEXIST, but be more careful. To avoid this, make the reader and writer a function that takes a path as an argument.
Rewrite your writer as int speak(const char *fifo, int pipefd) and your reader as int tick(const char *fifo).
Then make a wrapper like this:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
const char fifo_name[] /* = ... */;
int speak(const char *fifo, int pipefd);
int tick(const char *fifo);
int main() {
int pipefd[2];
pipe(pipefd);
mknod(fifo_name, S_IFIFO | 0666, 0);
if (fork() == 0) {
close(pipefd[0]);
return speak(fifo_name, pipefd[1]);
} else {
close(pipefd[1]);
char foo;
read(pipefd[0], &foo, 1);
return tick(fifo_name);
}
}
Modify your writer to print a byte (of anything) to the passed fd after the fifo is created (i.e. right after the call to open(..., O_WRONLY)).
Don't use my code verbatim, as I've omitted error checking for the sake of brevity.
it runs ok in my env. and if reader and writer is ready, open will return. because open is blocked, so in my opinion, mknod function is success. May be you excute these two process at different path.

Resources