setrlimit() does not change values - c

My computer accepts 380 threads per process. I try to increase to a larger number, using settlimit () but I have the expected result.
How I can increase the number of process?
The following code does not work properly:
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <errno.h>
void *doSomeThing()
{
pthread_detach(pthread_self());
sleep(1);
pthread_exit(NULL);
}
int main(void)
{
struct rlimit rlim;
pthread_t tid;
int i;
if (getrlimit(RLIMIT_NPROC, &rlim) != 0) {
printf("Can't call getrlimit(): [%s]\n", strerror(errno));
exit(0);
}
rlim.rlim_cur = 1000;
rlim.rlim_max = 1200;
if (setrlimit64(RLIMIT_NPROC, &rlim) != 0) {
printf("Error: getrlimit()\n");
exit(0);
}
/* Create threads */
for (i=0; i<385; i++) {
if (pthread_create(&tid, NULL, doSomeThing, NULL) != 0)
printf("Can't create thread %d:[%s]\n", i, strerror(errno));
}
}

Decrease the size of the pthread stack, this should allow you to fit more threads on your system.
pthread_attr_init(&attr);
assert(pthread_attr_setstacksize(&attr, 1<<16) == 0);
for (i=0; i<2048; i++)
assert(pthread_create(&tid, &attr, doSomeThing, NULL) == 0);
Alternatively, decrease your stack size using setrlimit
rlim.rlim_cur=4096;
rlim.rlim_max=4096;
setrlimit64(RLIMIT_NPROC, &rlim);

Related

Convert Pthread to process fork()

With this basic pthread code below, what is the method to convert pthread_create to fork() and achieve a similar outcome.
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
sem_t mutex;
void* wait_t(void* a)
{
(int)a--;
if ((int)a < 0)
{
sem_wait(&mutex);
printf("waiting\n");
}
}
void* signal_t(void* a)
{
(int)a++;
if ((int)a <= 0)
{
printf("signal\n");
sem_post(&mutex);
}
}
int main()
{
sem_init(&mutex, 0, 1);
int i = -2;
pthread_t t1, t2;
pthread_create(&t1, NULL, wait_t, i);
pthread_create(&t2, NULL, signal_t, i);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
exit(0);
}
Unless I'm missing something, the following code allows you to achieve the same functionality using processes instead of threads.
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
sem_t mutex;
void wait_t(int a)
{
a--;
if (a < 0)
{
sem_wait(&mutex);
printf("waiting\n");
}
}
void signal_t(int a)
{
a++;
if (a <= 0)
{
printf("signal\n");
sem_post(&mutex);
}
}
int main()
{
sem_init(&mutex, 0, 1);
int i = -2;
if(fork() == 0){ // create 1st child process
wait_t(i);
exit(0);
}
if(fork() == 0){ // create 2nd child process
signal_t(i);
exit(0);
}
wait(NULL);
wait(NULL);
exit(0);
}
Note: I'm not validating any possible errors thrown by fork() as it is advisable to do.

Shared Memory and semaphores: Unexpected segmantation fault

I'm trying to create 2 programs consisting of a producer and a consumer. The producer generates a set amount of random numbers from 0 to 9 and stores them in a circular_queue in shared memory and then the consumer reads the queue from shared memory and prints the frequency of each number from 0 to 9.
The producer is not giving me an error. However, when I try to run the consumer, the program immediately gives a segmentation fault. I was hoping someone could detect what is wrong. I also wanted to know if there is any way for me to check the dev/shm directory to verify that the shared memory file I'm trying to create is working? Thanks
PRODUCER
#include <fcntl.h>
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include "cola_circular.c"
#define SHM_NAME "/shm_eje4"
#define QUEUE_SIZE 10
typedef struct {
circular_queue queue;
sem_t sem_mutex;
} ShmStruct;
int main(int argc, char *argv[]) {
int fd_shm;
int i;
pid_t ppid = 0;
pid_t pid = 0;
ShmStruct *input;
if (argc < 3) {
fprintf(stderr,"usage: %s <n_numbers> <generation_method>", argv[0]);
return EXIT_FAILURE;
} else {
if (atoi(argv[1]) < 0) {
fprintf(stderr,"<n_numbers> has to be greater than or equal to 0");
return EXIT_FAILURE;
}
if (atoi(argv[2]) < 0 || atoi(argv[2]) > 1) {
fprintf(stderr,"<generation_method>: 0 for random, 1 for sequential");
return EXIT_FAILURE;
}
}
/* Crear memoria compartida para la cola, semafaros */
fd_shm = shm_open(SHM_NAME,
O_RDWR | O_CREAT | O_EXCL,
S_IRUSR | S_IWUSR);
if (fd_shm == -1) {
fprintf(stderr, "Error creating the shared memory segments");
shm_unlink(SHM_NAME);
return EXIT_FAILURE;
}
/* Cambiar el tamaño del segmento de memoria */
if (ftruncate(fd_shm, sizeof(ShmStruct)) == -1) {
fprintf(stderr, "Error resizing the shared memory segment\n");
shm_unlink(SHM_NAME);
close(fd_shm);
return EXIT_FAILURE;
}
/* Mapear el segmento de memoria */
input = mmap(NULL,
sizeof(*input),
PROT_READ | PROT_WRITE, MAP_SHARED,
fd_shm,
0);
close(fd_shm);
if (input == MAP_FAILED) {
fprintf(stderr, "Error mapping the shared memory segment\n");
shm_unlink(SHM_NAME);
close(fd_shm);
return EXIT_FAILURE;
}
if (sem_init(&(input->sem_mutex),1,1) < 0) {
fprintf(stderr, "Error initializing mutex semaphore\n");
perror("sem_init");
return EXIT_FAILURE;
}
input->queue = queue_ini(QUEUE_SIZE);
/*Generamos N numeros aleatorios/secuencia entre 0 y 9*/
sem_wait(&(input->sem_mutex));
if (argv[2] == 0) {
for (i=0; i<atoi(argv[1]); i++) {
insert_queue(input->queue, rand()%10);
}
} else if (atoi(argv[2]) == 1) {
for (i=0; i<atoi(argv[1]); i++) {
insert_queue(input->queue, i%10);
}
}
sem_post(&(input->sem_mutex));
/*El programa espera un caracter mientras ejecutamos el hijo*/
getchar();
sem_destroy(&(input->sem_mutex));
munmap(input, sizeof(*input));
shm_unlink(SHM_NAME);
close(fd_shm);
return EXIT_SUCCESS;
}
CONSUMER
#include <errno.h>
#include <fcntl.h>
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include "cola_circular.c"
#define SHM_NAME "/shm_eje4"
typedef struct {
circular_queue queue;
sem_t sem_mutex;
} ShmStruct;
int main(void) {
fprintf(stdout, "1");
int i;
int count[10];
int fd_shm = shm_open(SHM_NAME,
O_RDONLY,
0);
if (fd_shm == -1) {
fprintf(stderr, "Error opening the shared memory segment\n");
return EXIT_FAILURE;
}
ShmStruct *output = mmap(NULL,
sizeof(*output),
PROT_READ,
MAP_SHARED,
fd_shm,
0);
close(fd_shm);
if (output == MAP_FAILED) {
fprintf(stderr, "Error mapping the shared memory segment\n");
return EXIT_FAILURE;
}
sem_wait(&(output->sem_mutex));
for (i=0; i<10; i++) {
count[i] = 0;
}
for (i=0; i<output->queue.num; i++) {
count[output->queue.queue[i]]++;
}
fprintf(stdout, "Histograma de numeros de queue:\n");
for (i=0; i<10; i++) {
fprintf(stdout, "%d ---> %d\n", i, count[i]);
}
sem_post(&(output->sem_mutex));
munmap(output, sizeof(*output));
close(fd_shm);
return EXIT_SUCCESS;
}
CIRCULAR QUEUE
#include <stdio.h>
#include <stdlib.h>
#define SIZE 124
typedef struct circular_queue {
int *queue;
int rear;
int front;
int size;
int num;
} circular_queue;
circular_queue queue_ini(int size) {
int i;
circular_queue ret;
ret.queue = (int*) malloc(0);
ret.rear = -1;
ret.front = -1;
ret.size = size;
ret.num = 0;
return ret;
}
int queue_isFull(circular_queue queue) {
if (queue.num == queue.size) {
return 1;
} else {
fprintf(stderr, "Error inseting, the queue is full.\n");
return 0;
}
}
int insert_queue(circular_queue queue, int num) {
if (queue_isFull(queue) == 1) {
return 0;
}
ret.queue = (int*) realloc(ret.queue, sizeof(int)*(ret.num+1));
if (queue.front == -1) queue.front = 0;
queue.rear = (queue.rear+1)%SIZE;
queue.queue[queue.rear] = num;
queue.num++;
fprintf(stdout, "\n Inserted --> %d", queue.num);
return 1;
}
int queue_isEmpty(circular_queue queue) {
if (queue.num == 0) return 1;
return 0;
}
ret.queue = (int*) realloc(sizeof(int)*(ret.num+1));
The realloc function doesn't allocate shared memory. If you don't put the queue in shared memory, it isn't shared. When you try to access pointers into regular memory allocated in one process from another process, the most common result would be a crash.
You need to put all shared data in shared memory. When you share pointers across processes, you need to share a relative pointer into the shared memory and each process needs to convert that into a pointer valid in its address space by adding in its particular base address of the shared memory segment.

Working with semaphores and shared memory under Linux

I need to write a program that is creating a N amount of sub processes and every single one of them adds one to a shared memory variable. My idea is to use semaphores and shared memory, but the processes are not waiting for each other and the shared memory variable is also not working as I want it.
mydefs.h
#ifndef __MYDEFS__H__
#define __MYDEFS__H__
// Includes
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <memory.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/shm.h>
#endif // __MYDEFS__H__
main.c
#include "mydefs.h"
#define PROC_COUNT 3
#define INITAL_MARKER_VALUE 0
#define PID_LEN 32
char mypid[PID_LEN];
int main()
{
int i, shm_id;
sem_t mutex;
if(sem_init(&mutex,1,1) < 0)
{
perror("semaphore initilization");
exit(0);
}
shm_id = shmget(IPC_PRIVATE, 4*sizeof(int), IPC_CREAT | 0666);
if (shm_id < 0) {
printf("shmget error\n");
}
int *shmpointer = shmat(shm_id,0,0);
memset(mypid, 0, sizeof(mypid));
sprintf(mypid, "%06d", getpid());
for(i = 0; i < PROC_COUNT; i++)
{
if (fork() == 0)
{
while(sem_wait(&mutex)!=0);
execl("slaveproc", "slaveproc", mypid, (char *)0);
shmpointer += 1;
sem_post(&mutex);
perror("\n Can't exec slave program. Cause ");
exit(1);
}
}
sleep(1);
printf("%d\n", *shmpointer);
return 0;
}
slaveproc.c
#include "mydefs.h"
int marker; // Marker value
int main(int argc, char *argv[])
{
master_pid = atoi(argv[1]);
printf("\n --------------------------------------");
printf("\n I'm the slave proc!");
printf("\n My pid: %d", getpid());
printf("\n My master's pid: %d", master_pid);
printf("\n --------------------------------------");
for(;;) pause();
return 0;
}
The problem (or at least "a problem") is that mutex is not in shared memory: it's allocated on the stack. When you fork(), the new process will have a completely separate copy from the old process, so calling sem_wait(&mutex) on one process will not affect the other process's mutex at all.
You should put mutex in the shared memory:
int main()
{
int i, shm_id;
shm_id = shmget(IPC_PRIVATE, sizeof(sem_t) + 4*sizeof(int), IPC_CREAT | 0666);
if (shm_id < 0) {
printf("shmget error\n");
}
int *shmpointer = shmat(shm_id,0,0);
sem_t *mutex = shmpointer;
shmpointer = (void*)shmpointer + sizeof(sem_t);
if(sem_init(mutex,1,1) < 0)
{
perror("semaphore initilization");
exit(0);
}
memset(mypid, 0, sizeof(mypid));
sprintf(mypid, "%06d", getpid());
for(i = 0; i < PROC_COUNT; i++)
{
if (fork() == 0)
{
while(sem_wait(mutex)!=0);
execl("slaveproc", "slaveproc", mypid, (char *)0);
shmpointer += 1;
sem_post(mutex);
perror("\n Can't exec slave program. Cause ");
exit(1);
}
}
sleep(1);
printf("%d\n", *shmpointer);
return 0;
}
You're also never writing to the memory in shmpointer (perhaps you meant (*shmpointer) += 1?), but I'll let you figure that out on your own.

Named Semaphore just not working

we had an exam today and we had a task to implement a "train-handler".
There are 7 trains represented by one process each. Each train arrives after a couple of seconds, checks if 1 of our 3 traintracks is available. If not, wait...
If track is free, enter it and lock it.
Stay for at the train station for a few seconds, leave and unlock it.
Me and a few friends are trying to make our program run but we just can't get it done. It seems to be the problem that our shared memory is not synchronized properly (semaphore). Using a mac, so I have to use named semaphores.
compiled with: "gcc -Wall -Werror -std=gnu99 -lpthread process_trains.c -o test"
CODE:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <time.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/wait.h>
#include <errno.h>
sem_t *sem;
int *shm_ptr;
int *initShm (int size) {
int shm_fd = 0;
if((shm_fd = shm_open("/shm", O_CREAT | O_RDWR, 0777)) == -1) {
perror("Error creating shared memory segment!");
}
if ((ftruncate(shm_fd, size)) == -1) {
perror("Error sizing shared memory segment!");
}
return (int*) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
}
int trainAboutToArrive(int arrive, int stay, int Y){
int Z=0;
//Zug kommt in "arrive" Sekunden an
sleep(arrive);
while (shm_ptr[Z]!=0) {
Z++;
if(Z==3){
Z=0;
}
}
sem_wait(sem);
shm_ptr[Z]=1;
sem_post(sem);
printf("Zug %d ist auf Gleis %d eingefahren\n", Y, 1+Z);
//Zug hat einen Aufenthalt von "stay" Sekunden
sleep(stay);
sem_wait(sem);
shm_ptr[Z]=0;
sem_post(sem);
sem_close(sem);
printf("Zug %d verlässt Gleis %d\n", Y, 1+Z);
return EXIT_SUCCESS;
}
int main(int argc, char const *argv[]) {
shm_unlink("shm");
int i=0, tracks=3, trains=7, status;
int arrival[]={0,0,3,2,5,4,2};
int stay[]={2,3,7,2,1,4,3};
off_t size = sizeof(int)*tracks;
shm_ptr = initShm(size);
if((sem = sem_open("/semap",O_CREAT,0644,1)) == SEM_FAILED) {
perror("client sem_open");
}
for (i=0; i < tracks; i++) {
shm_ptr[i]= 0;
}
pid_t pids[trains];
for (i = 0; i < trains; i++) {
pids[i] = fork();
if(pids[i] == -1) {
perror("Error creating train-process!!");
} else if (pids[i] == 0) {
trainAboutToArrive(arrival[i], stay[i], 1+i);
exit(0);
}else if (pids[i] > 0) {
}
}
for(i=0; i < trains; i++){
waitpid(pids[i], &status, 0);
}
shm_unlink("shm");
return EXIT_SUCCESS;
}
Link with -pthread!!!! man page of all used semaphore functions tells us >.<
Thanks for everyones help!!
And for everyone who's interested, this is my code now. I improved a lot of things I didn't have time for in the exam. This runs perfectly and in my "beginners-eyes" this is not improvable by using the given functions (semaphores, shared mem...). If it is, I'd be grateful for tips & tricks ;)
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/wait.h>
#include <errno.h>
int *shm_ptr;
int *initShm (off_t size) {
int shm_fd = 0;
if((shm_fd = shm_open("/shm", O_CREAT | O_RDWR, 0777)) == -1) {
perror("Error creating shared memory segment!");
}
if ((ftruncate(shm_fd, size)) == -1) {
perror("Error sizing shared memory segment!");
}
return (int*) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
}
void initSem(sem_t **plats) {
if((plats[0] = sem_open("/one",O_CREAT,0644,1)) == SEM_FAILED) {
perror("client sem_open");
}
if((plats[1] = sem_open("/two",O_CREAT,0644,1)) == SEM_FAILED) {
perror("client sem_open");
}
if((plats[2] = sem_open("/three",O_CREAT,0644,1)) == SEM_FAILED) {
perror("client sem_open");
}
}
int trainAboutToArrive(int arrive, int stay, int train, sem_t **plats){
srand(getpid());
int platform = rand()%3;
sleep(arrive);
while (3) {
sem_wait(plats[platform]);
if(shm_ptr[platform]==0){
shm_ptr[platform]=1;
break;
}
sem_post(plats[platform]);
platform = rand() % 3;
}
printf("Train %d enters platform %d\n", train, 1+platform);
sleep(stay);
shm_ptr[platform]=0;
printf("Train %d leaves platform %d\n", train, 1+platform);
sem_post(plats[platform]);
sem_close(plats[platform]);
return EXIT_SUCCESS;
}
int main(int argc, char const *argv[]) {
shm_unlink("/shm");
sem_unlink("/one");
sem_unlink("/two");
sem_unlink("/three");
int i=0, tracks=3, trains=7, status;
int arrival[]={0,0,3,2,5,4,2};
int stay[]={2,3,7,2,1,4,3};
sem_t *plats[3];
off_t size = sizeof(int)*tracks;
shm_ptr = initShm(size);
initSem(plats);
for (i=0; i < tracks; i++) {
shm_ptr[i]= 0;
}
pid_t pids[trains];
for (i = 0; i < trains; i++) {
pids[i] = fork();
if(pids[i] == -1) {
perror("Error creating train-process!!");
} else if (pids[i] == 0) {
trainAboutToArrive(arrival[i], stay[i], 1+i, plats);
exit(0);
}else if (pids[i] > 0) {
}
}
for(i=0; i < trains; i++){
waitpid(pids[i], &status, 0);
}
shm_unlink("/shm");
sem_unlink("/one");
sem_unlink("/two");
sem_unlink("/three");
return EXIT_SUCCESS;
}

any example of copy_from_user() ? kernel and userspace

I am looking for copying PID value from User space to Kernel space, here is my code snaps.
Kernel Module:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/siginfo.h>
#include <linux/rcupdate.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/signal.h>
MODULE_LICENSE ("GPL");
struct siginfo sinfo;
pid_t pid;
struct task_struct *task;
int init_module()
{
memset(&sinfo, 0, sizeof(struct siginfo));
sinfo.si_signo = SIGIO;
sinfo.si_code = SI_USER;
pid = 5218; // Everytime a new PID
// task = find_task_by_vpid(pid); I am also working on new and old version of UBUNTU so thats why this is here
task = pid_task(find_vpid(pid), PIDTYPE_PID);
printk("%d .\n", task);
if(task == NULL) {
printk("Cannot find PID from user program\r\n");
return 0;
}
send_sig_info(SIGIO, &sinfo, task);
return 0;
}
void cleanup_module ()
{
printk(KERN_ALERT"\nGoodBye World\n\n");
}
Userspace Code:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
void signal_handler(int signum)
{
if (signum == SIGIO) printf("SIGIO\r\n"); return;
}
int main()
{
int i = 1;
signal(SIGIO, signal_handler);
printf("My PID is %d.\n", getpid());
while (i);
return 0;
}
Now, here I am always running user space program to get PID and then I always have to edit the pid variable in Kernel module.
I found one way to access information from user space into Kernel space and vice-versa (i.e., using copy_from/to_user() )
But I am unable to understand either of them for getting a PID from user space, I have to make file in /dev directory and should apply all the required functions for just getting PID?
Is there any other way? if not, then can anyone please help me to do this? I am new in c programming and playing with kernel module directly so its hard for me.
Look into code you have given, it seems that you want to handle SIGIO signal
Here is my attempt to solve your problem,
signal_kernel.c file :
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/siginfo.h>
#include <linux/rcupdate.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/signal.h>
#include <linux/debugfs.h>
#include <linux/pid.h>
#define MAX 10
MODULE_LICENSE("GPL");
struct dentry *file;
static ssize_t write_conf_pid(struct file *file, const char *buf,
size_t count, loff_t *position)
{
char temp_str[MAX];
int ret;
int pid = 0;
struct siginfo sinfo;
struct task_struct *task;
/* NEVER TRUST USER INPUT */
if (count > MAX)
return -EINVAL;
if (copy_from_user(temp_str, buf, MAX) != 0)
return -EFAULT;
ret = sscanf(temp_str, "%d", &pid);
if (ret != 1) {
pr_info("Error in reading PID value from user");
return -EINVAL;
}
pr_info("User entered pid %d\n", pid);
memset(&sinfo, 0, sizeof(struct siginfo));
sinfo.si_signo = SIGIO;
sinfo.si_code = SI_USER;
task = pid_task(find_vpid(pid), PIDTYPE_PID);
if (task == NULL) {
pr_info("Cannot find PID from user program\r\n");
return -ENODEV;
}
ret = send_sig_info(SIGIO, &sinfo, task);
if (ret < 0)
pr_info("Error sending signal\n");
return count;
}
static const struct file_operations my_fops = {
.write = write_conf_pid,
};
int init_module()
{
/* Only root can write to this file */
file = debugfs_create_file("pidconf", 0200, NULL, NULL, &my_fops);
return 0;
}
void cleanup_module()
{
pr_info("\nGoodBye World\n\n");
}
signal_user.c file :
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
void signal_handler(int signum)
{
if (signum == SIGIO)
printf("SIGIO\r\n");
return;
}
int main()
{
int i = 1;
signal(SIGIO, signal_handler);
printf("My PID is %d.\n", getpid());
while (i);
return 0;
}
After compiling and running both user space and kernel space program, use debugfs interface to send PID value to Kernel space,
$ insmod signal_kernel.ko
$ ./signal_user
My PID is 17633.
... # Process will run in loop due to while(1)
From another terminal, provide PID to debugfs interface,
$ echo 17633 > /sys/kernel/debug/pidconf
There are various ways (sysfs, misc_char_device, char device etc.) to this task, but this will give you brief idea about using copy_from_user() and copy_to_user()
Please note that there is little error handling done in signal_user.c and signal_kernel.c.

Resources