Hi. I'm a beginner in C and system programming. I need to use multiple process and POSIX shared memory to find all primes between 0 and 100. My code compiles, but the result is not correct, it shows all the multiples of 3 as primes.
My instructor also mentioned that the multi-process portion will fork() the appropriate number of child processes. The parent process will create a POSIX shared memory object to which the sub-processes will attach. I am confused about the things he said about parent process.
Can someone take a look at my code and let me know why I'm not getting the right primes? Your help is greatly appreciated.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <getopt.h>
#include <ctype.h>
#include <stdint.h>
#include <unistd.h>
#include <math.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#define BITS_PER_WORD 8
#define WORD_OFFSET(b) ((b) / BITS_PER_WORD)
#define BIT_OFFSET(b) ((b) % BITS_PER_WORD)
#define SHM_NAME "/cc_prm"
//function to set all non-primes to 0
void set_notPrime(unsigned int n);
void set_bitmap();
void seed_primes();
int check_Prime(unsigned int n);
unsigned long next_seed(unsigned long cur_seed);
void count_primes();
void prime_process();
void *mount_shmem(char *path, int object_size);
void sieve(unsigned long i);
void nevermore();
//global variables
unsigned long m = 100; //maximum number
int c = 5; //number of processes
char *prime_nums = NULL;
pid_t *process_array;
int tot_p_num = 0; //total number of primes found
int main (int argc, char *argv[])
{
//print n and c
printf("m=%ld, c=%d\n", m, c);
struct sigaction action;
sigemptyset(&action.sa_mask);
//action.sa_handler = nevermore();
action.sa_flags = 0;
sigaction(SIGQUIT, &action, NULL);
sigaction(SIGINT, &action, NULL);
sigaction(SIGHUP, &action, NULL);
unsigned long primes_size = m / BITS_PER_WORD + 1;
void *addr = mount_shmem(SHM_NAME, primes_size);
printf("Memory is mounted\n");
prime_nums = (unsigned char *) addr;
set_bitmap();
printf("Bitmap is set\n");
seed_primes();
printf("Primes are seeded\n");
prime_process();
printf("children have lived and died\n");
count_primes();
shm_unlink(SHM_NAME);
int pid = 0;
while((pid=wait(NULL))!= -1)
{
continue;
}
if(errno!=ECHILD)
{
perror("couldn't kill child processes\n");
}
free(process_array);
printf("everything has been freed\n");
return 0;
}
void set_bitmap()
{
prime_nums[0] = 0x00;
unsigned long i;
for (i = 1; i < (m/BITS_PER_WORD); i++)
{
prime_nums[i] = 0x01;
}
}
void seed_primes()
{
unsigned long i;
unsigned long j=3;
unsigned long sqrt_n = sqrt(sqrt(m));
while (j <= sqrt_n + 1)
{
for (i = j; i*j <= sqrt(m)+1; i++)
{
set_notPrime;
}
j++;
while(!check_Prime(j))
{
j++;
}
}
}
void set_notPrime(unsigned int n)
{
prime_nums[WORD_OFFSET(n)] |= (1 << BIT_OFFSET(n));
}
int check_Prime(unsigned int n)
{
char bit = prime_nums[WORD_OFFSET(n)] & (1 << BIT_OFFSET(n));
return bit == 0;
}
void prime_process()
{
int i;
for (i = 0; i < c; i++)
{
process_array = malloc(sizeof(pid_t) * c);
pid_t pid;
switch (pid = fork())
{
case -1:
perror("Forking Error");
exit(EXIT_FAILURE);
break;
//This is the child
case 0:
sieve(i);
exit(EXIT_SUCCESS);
break;
//This is the parent
default:
process_array[i] = pid;
break;
}
}
}
void *mount_shmem(char *path, int object_size)
{
int shmem_fd;
void *addr;
//create and resize the file
shmem_fd = shm_open(path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (shmem_fd == -1)
{
perror("Can't open shared memory");
exit(EXIT_FAILURE);
}
//resize the file
if (ftruncate(shmem_fd, object_size) == -1)
{
perror("Can't resize shared memory");
exit(EXIT_FAILURE);
}
/* map the shared memory object */
addr = mmap(NULL, object_size, PROT_READ | PROT_WRITE, MAP_SHARED,
shmem_fd, 0);
if (addr == MAP_FAILED)
{
perror("Failure mapping shared memory");
exit(EXIT_FAILURE);
}
return addr;
}
unsigned long next_seed(unsigned long cur_seed)
{
unsigned long i;
for (i = cur_seed + 1; i <= sqrt(m); i++)
if (check_Prime(i) == 1)
return i;
return 0;
}
void sieve(unsigned long i)
{
unsigned long min = i * (m / c) + 1;
unsigned long max =(i == c - 1) ? m : min + (m / c) - 1;
unsigned long j;
unsigned long k;
j = 1;
while ((j = next_seed(j)) != 0)
{
for (k = (min / j < 3) ? 3 : (min / j);(j * k) <= max;k++)
{
set_notPrime(j * k);
}
}
}
void count_primes()
{
unsigned long i;
if(m >= 2)
{
printf("2\t");
tot_p_num++; //2 is prime, add 1 to tot_p_num
}
for(i=3;i<=m; i = i+2)
{
if(check_Prime(i))
{
printf("%lu\t",i);
tot_p_num++;
if (tot_p_num % 8 == 0)
printf("\n");
}
}
printf("\nThere are %d primes between 0 and %lu\n", tot_p_num, m);
}
void nevermore()
{
;
}