Unexpected Segmentation Fault in pthread Program - c

So a foreword, I am new to C, so please forgive any horrifying mistakes my program has.
I am trying to write a program that will take a list of numbers passed in as arguments to the program or contained in a file whose path is passed in.
It stores the numbers into an array, and stores how many numbers there are into the first element of the array. It will only store up to 100 numbers.
It then creates a pthread and passes the pointer to the array to the thread.
The thread is then suppose to sum up the numbers and return the sum back to the main function.
I am experiencing the following issues:
1. It doesn't always happen, but sometimes I get a segmentation fault right before the line of code that says:
printf("Begining to create the thread");
2. My attempts to return the sum isn't working, and after hours of research online, I can't figure out why.
3. When I compile the program, I get the following errors:
gcc -g -o assn3 assn3.c -pthread
assn3.c: In function ‘AddUpNumbers’:
assn3.c:34:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
return (void*)total;
^
assn3.c: In function ‘main’:
assn3.c:96:3: warning: passing argument 1 of ‘pthread_join’ makes integer from pointer without a cast [enabled by default]
pthread_join(&functionThread, &total);
^
In file included from assn3.c:12:0:
/usr/include/pthread.h:261:12: note: expected ‘pthread_t’ but argument is of type ‘pthread_t *’
extern int pthread_join (pthread_t __th, void **__thread_return);
^
assn3.c:97:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘void *’ [-Wformat=]
printf("The total returned by the thread is %d", total);
^
Here's my code:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NO_ARGS 1
#define ONLY_SINGLE_ARG 2
#define PATH_TO_READ_FROM 1
#define MAX_NUMBERS 101
#define MAX_CHAR_INPUT 255
#define COUNT_LOCATION 0
void* AddUpNumbers(void* arrayPointer) {
printf("Created the pthread!");
int* numbersArray = (int*)arrayPointer;
int count = numbersArray[COUNT_LOCATION];
int total = 0;
int i = 1;
while (i < count) {
total = total + numbersArray[i];
}
printf("The total to be returned is %d", total);
return (void*)total;
}
int main(int argc, char* argv[]) {
FILE * numbersFile = NULL;
int count = 0;
int numberArray[MAX_NUMBERS];
//Initialize the Array
int i = 0;
while (i < MAX_NUMBERS) {
numberArray[i] = 0;
i = i + 1;
}
if (argc == NO_ARGS) {
printf("Usage: # or file path, #, #, ..., #\n");
} else if (argc == ONLY_SINGLE_ARG) {
numbersFile = fopen(argv[PATH_TO_READ_FROM], "r");
if (numbersFile != NULL) {
char buff[MAX_CHAR_INPUT];
i = 1;
count = 0;
while (i < MAX_NUMBERS) {
if (fscanf(numbersFile, "%s", buff) != EOF) {
numberArray[i] = atoi(buff);
printf("%d\n", numberArray[i]);
i = i + 1;
count = count + 1;
} else {
break;
}
}
numberArray[COUNT_LOCATION] = count;
printf("Count Total: %d\n", numberArray[COUNT_LOCATION]);
} else {
printf("Error: Could not open file!\n");
return -1;
}
} else if (argc < MAX_NUMBERS + 1) {
i = 1;
count = 0;
while (i < argc) {
numberArray[i] = atoi(argv[i]);
printf("%d\n", numberArray[i]);
i = i + 1;
count = count + 1;
}
printf("See if error happens after this");
numberArray[COUNT_LOCATION] = count;
printf("Count Total: %d\n", numberArray[COUNT_LOCATION]);
} else {
printf("Too many numbers! This program can only add up to: %d numbers.\n", MAX_NUMBERS);
return -1;
}
printf("Begining to create the thread");
pthread_t functionThread;
int creationSuccess = 0;
void* total;
creationSuccess = pthread_create(&functionThread, NULL, AddUpNumbers, (void*)numberArray);
if (creationSuccess == 0) {
pthread_join(&functionThread, total);
printf("The total returned by the thread is %d", *((int)total));
} else {
printf("Something went wrong.\n");
}
if (numbersFile != NULL) {
fclose(numbersFile);
}
return 0;
}
My Makefile looks like this:
assn3: assn3.c
gcc -g -o assn3 assn3.c -pthread

You should be very wary of compiler warnings. Either clean them up or understand very well why they are ok. Pay special attention to warnings about data type mismatches.
In this case this warning probably explains the main problem:
In file included from assn3.c:12:0:
/usr/include/pthread.h:261:12: note: expected ‘pthread_t’ but argument is of type ‘pthread_t *’
extern int pthread_join (pthread_t __th, void **__thread_return);
^
You are (creating and) passing a pointer to your pthread_t object as the first argument of pthread_join(), but unlike pthread_create(), pthread_join() expects you to pass the pthread_t itself, not a pointer to it. All manner of havoc (technically, "undefined behavior") will ensue.
UPDATE: Additionally, the second argument you are passing to pthread_join() is an uninitialized pointer to void. If pthread_create() tries to write anything where it points then who knows what happens (undefined behavior again). You are expected to pass a valid pointer to the location where the result is to be written. In this case, that would be &total.

The syntax of pthread_create is:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, *(*start_routine) (void *), void *arg);
pthread_t - is id of thread. So create variable pthread_t id, or array of values if you have a lot of threads, like pthread_t id[THREAD_NUM];
Then your func will looks like:
pthread_create(&id[i], NULL, &functionThread, (void*)numberArray);
With pthread_join(&functionThread, total);
The same thing.
int pthread_join(pthread_t thread, void **value_ptr);
So you join must look like:
pthread_join(&id[i], total);

Related

Round Robin Scheduler in C

I need a bit of help with my round robin scheduler. It is meant to take external C files and place them in a queue while displaying their current state, and execute them through round robin scheduling. Here is what I have so far:
#include<pthread.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
enum states {running, ready, waiting, idle};
struct process{
//command to run process
enum states state;
int id;
};
struct process procs[5];
int procSize = 5;
void *runProcess(struct process *p)
{
while(1)
{
printf("Process %i is running", p->id);
sleep(1);
}
}
void *takeInput(void *vargp)
{
//print process statuses when 'procs' is entered
while(1)
{
char *str[64];
fgets(str, 64, stdin);
if (strcmp(str, "procs"))
{
for (int i = 0; i < procSize; i++)
{
printf("Process %i: %i\n", procs[i].id, procs[i].state);
}
}
}
}
void *schedule(void *vargp)
{
struct process p = procs[0];
if (p.state == idle)
{
p.state = ready;
}
if (p.state == ready)
{
p.state = running;
pthread_t run;
pthread_create(&run, NULL, runProcess, &p);
//pthread_join(run, NULL);
sleep(5);
pthread_cancel(run);
p.state = ready;
for(int i = procSize - 1; i > 0; i--)
{
procs[i-1] = procs[i];
}
procs[procSize] = p;
}
else if (p.state == waiting)
{
for(int i = procSize - 1; i > 0; i--)
{
procs[i-1] = procs[i];
}
procs[procSize] = p;
}
}
int main()
{
for (int i = 0; i < 5; i++)
{
struct process p;
p.state = idle;
p.id = i;
procs[i] = p;
}
pthread_t schedulerid;
pthread_t inputid;
pthread_create(&schedulerid, NULL, schedule, NULL);
//pthread_join(schedulerid, NULL);
pthread_create(&inputid, NULL, takeInput, NULL);
//pthread_join(inputid, NULL);
}
When I attempt to run this, I get no errors, only warnings, and nothing happens. What do I need to improve on? Is there an issue with trying to call functions using threads? Any help is appreciated.
UPDATED WITH WARNINGS:
Sched.c:35:20: warning: passing argument 1 of ‘strcmp’ from incompatible pointer type [-Wincompatible-pointer-types]
35 | if (strcmp(str, "procs"))
| ^~~
| |
| char **
In file included from Sched.c:3:
/usr/include/string.h:137:32: note: expected ‘const char *’ but argument is of type ‘char **’
137 | extern int strcmp (const char *__s1, const char *__s2)
| ~~~~~~~~~~~~^~~~
Sched.c: In function ‘schedule’:
Sched.c:56:36: warning: passing argument 3 of ‘pthread_create’ from incompatible pointer type [-Wincompatible-pointer-types]
56 | pthread_create(&run, NULL, runProcess, &p);
| ^~~~~~~~~~
| |
| void * (*)(struct process *)
In file included from Sched.c:1:
/usr/include/pthread.h:200:15: note: expected ‘void * (*)(void *)’ but argument is of type ‘void * (*)(struct process *)’
200 | void *(*__start_routine) (void *),
| ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
Lets fix those warnings
char *str[64];
fgets(str, 64, stdin);
if (strcmp(str, "procs"))
should be
char str[64];
fgets(str, 64, stdin);
if (strcmp(str, "procs"))
then
pthread_create(&run, NULL, runProcess, &p);
The function must be a void* func (void*)
So change run process to
void *runProcess(void *v)
{
struct process *p =(struct process*)v;
while(1)
{
printf("Process %i is running", p->id);
sleep(1);
}
}
ie pass a void * and cast it to what you need
this compiles with no warning now.
Finally put your joins back in
int pt1 = pthread_create(&schedulerid, NULL, schedule, NULL);
int pt2 = pthread_create(&inputid, NULL, takeInput, NULL);
printf("%d %d \n", pt1, pt2);
pthread_join(schedulerid, NULL);
pthread_join(inputid, NULL);
as a final note - you really must test the returns from all your system calls to make sure they worked
here it is running
pm100#paul-think:~/ut$ gcc ggg.c -g -lpthread
pm100#paul-think:~/ut$ ./a.out
Process 0 is running

Producers and Consumers with semaphores and threads

I am currently having issues this code. The only part of the code that is having error is "io_production_report(thread_args[0].Produced, pointer);".
The terminal mentions the error as follows"
driver.cpp: In function ‘int main(int, char**)’:
driver.cpp:83:51: error: cannot convert ‘int (*)[2]’ to ‘int**’
83 | io_production_report(thread_args[0].Produced, pointer);
| ^~~~~~~
| |
| int (*)[2]
In file included from driver.cpp:2:
io.h:49:48: note: initializing argument 2 of ‘void io_production_report(int*, int**)’
49 | void io_production_report(int produced[], int *consumed[]);
| ~~~~~^~~~~~~~~~
make: *** [Makefile:8: driver.o] Error 1
I am having problems implementing an array of pointers.
If anyone can help me that would be great!! :
driver.cpp
// Print Production Report
int pointer[2][2];
pointer[0][0]=thread_args[0].Consumed[0]; //Ethel
pointer[0][1]=thread_args[0].Consumed[1]; //Lucy
pointer[1][0]=thread_args[1].Consumed[0];
pointer[1][1]=thread_args[1].Consumed[1];
io_production_report(thread_args[0].Produced, pointer); //NEED HELP ON THIS LINE
driver.h
struct args {
sem_t *mutexOnBelt;
sem_t *frogMax;
sem_t *beltMax;
sem_t *candiesOnBelt;
sem_t *produceMax;
sem_t *consumeMax;
string *belt;
int *head;
int *tail;
int wait_time;
int produced;
string *name;
int Consumed[2];
int onBelt[2];
int Produced[2];
};
int option = 0;
int flagValues[4] = {0, 0, 0, 0};
io.c
/*
* void io_production_report(int produced[], int *consumed[])
* Show how many candies of each type produced. Show how many candies consumed by
* each consumer.
* produced[] - count for each ProductType
* *consumed[] - array of pointers to consumed arrays
* e.g. consumed[Lucy] points to an array that is indexed by product name
*/
void io_production_report(int produced[], int *consumed[]) {
int p, c; /* array indices */
int total;
printf("\nPRODUCTION REPORT\n----------------------------------------\n");
/* show number produced for each producer / candy type */
for (p=0; p < ProductTypeN; p++) {
printf("%s producer generated %d candies\n",
ProducerNames[p], produced[p]);
}
/* show number consumed by each consumer */
for (c=0; c < ConsumerTypeN; c++) {
printf("%s consumed ", ConsumerNames[c]);
total = 0;
for (p=0; p < ProductTypeN; p++) {
if (p > 0)
printf(" + ");
total += consumed[c][p];
printf("%d %s", consumed[c][p], ProducerAbbrevs[p]);
}
printf(" = %d total\n", total);
}
printf("Elapsed time %.3f s\n", elapsed_s());
}
As explained in the comments you need to make a pointer to the first element of your array, id est: you specify you array[N][M] as int (*)[M], working example:
#include <stdio.h>
void io_production_report(int (*)[2]);
void io_production_report(int (*consumed)[2]) {
for (int i = 0; i <4; i++)
printf("%d\n", consumed[i/2][i%2]);
}
int main(void) {
int pointer[2][2];
pointer[0][0]=1; //Ethel
pointer[0][1]=2; //Lucy
pointer[1][0]=3;
pointer[1][1]=4;
io_production_report(pointer);
}

Convert/compare an integer to a string in C and error in a 'for' cycle

I have this piece of code, that doesn't work like it should. This function is connected with another one, where I ask for a city and a date. Then, after confirming both exist in the file, this function calls this new one, down below.
I know I can't compare a string with an integer, I know that is possible to convert in one another, but I don't know how to do it and if I can do it in this case. id is an integer, and meteo_city_id is a string present in a struct. I have this problem in the second part of the condition in the if inside the for.
At the same time, in the same for, I have i < 152. This is the number of rows that exist in a file I have to use. However, the user can add lines in the file so, after adding a new one, that code doesn't work anymore. So what can I replace 152 so that cycle for works, regardless of the number of rows that are added later?
Thanks for the help. Here is the function:
#define TAM_STR 100
typedef struct city_t{
char city_id[TAM_STR];
char city_name[TAM_STR];
char county_name[TAM_STR];
char district_name[TAM_STR];} city_t;
typedef struct meteo_t{
char meteo_id[TAM_STR];
char meteo_city_id[TAM_STR];
char tempt_max[TAM_STR];
char tempt_min[TAM_STR];
char humidity[TAM_STR];
char pressure[TAM_STR];
char date[11];} meteo_t;
city_t *read_meteo(const char *filename, size_t *len)
{
if(filename == NULL || len == NULL)
return NULL;
FILE *fp = fopen(filename, "r");
if(fp == NULL)
{
fprintf(stderr, "Could not open %s: %s\n", "meteo.csv", strerror(errno));
return NULL;
}
meteo_t *arr = NULL, *tmp;
*len = 0;
char line[1024];
while(fgets(line, sizeof line, fp))
{
tmp = realloc(arr, (*len + 1) * sizeof *arr);
if(tmp == NULL)
{
fprintf(stderr, "could not parse the whole file %s\n", "meteorologia.csv");
if(*len == 0)
{
free(arr);
arr = NULL;
}
return arr;
}
arr = tmp;
sscanf(line, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%s", (arr[*len].meteo_id), (arr[*len].meteo_city_id), (arr[*len].tempt_max), (arr[*len].tempt_min), (arr[*len].humidity), (arr[*len].preassure), (arr[*len].date));
(*len)++;
}
fclose(fp);
if(*len == 0)
{
free(arr);
arr = NULL;
}
return arr;
}
void search_meteo_by_city_by_date(meteo_t *meteo, size_t len, const char *city, const int id, const char *date){
bool find = false;
if(meteo == NULL || city == NULL || id == NULL || date == NULL) {
printf("ERROR");
}
for(size_t i = 0; i < 152; ++i) {
if (strcasecmp(date, meteo[i].date) == 0 && id == meteo[i].meteo_city_id) {
find = true;
printf("Information for: %s in %s \nMaximum Temperature: %s ºC\nMinimum Temperature: %s ºC\nHumidity: %s \nPressure: %s hPa\n\n\n", city, date, meteo[i].tempt_max, meteo[i].tempt_min, meteo[i].humidity, meteo[i].preassure);
}
}
if(find == false) {
printf("No results were found for: %s\n", city);
}
}
void search_date_by_city() {
size_t cities_len;
city_t *cities = read_cities("cities.csv", &cities_len);
char local[100];
char date[100];
// error
if(cities == NULL) {
printf("ERROR");
}
printf("City: ");
scanf("%[^\n]%*c", local);
int id = search_for_city_by_name(cities, &cities_len, cidade);
if(id == -1) {
printf("That city doesn't exist\n");
return;
}
printf("Date: ");
scanf("%[^\n]%*c", date);
size_t meteo_len;
meteo_t *meteo = read_meteo("meteo.csv", &meteo_len);
if(meteo == NULL) {
printf("ERROR");
}
search_meteo_by_city_by_date(meteo, &meteo_len, local, id, date);
}
The file cities.csv has 152 rows and 4 columns, such as
id,city,county,district
The file meteo.csv has 152 rows and 7 cloumns, such as
meteo_id,meteo_city_id,tempt_max,tempt_min,humidity,pressure,date
the function: search_meteo_by_city_by_date() is expecting the parameter len to contain the actual number of entries, However, where that function is being called, what is being passed is the ADDRESS of the variable that contains the actual number of entries.
Suggest replace this:
search_meteo_by_city_by_date(meteo, &meteo_len, local, id, date);
with this:
search_meteo_by_city_by_date(meteo, meteo_len, local, id, date);
which is passing the contents of metro_len rather than the address of metro_len
then replace this:
for(size_t i = 0; i < 152; ++i)
with
for(size_t i = 0; i < len; ++i)
So you need to know the number of lines in a file. Can you simply count the number of line feeds or carriage returns ?
I can’t see your implementation of read_meteo but I presume you can add something in there that counts the number of lines in the file.
Also, atoi() might be useful to convert a string number to an int.
The larger solution
Always compile with all warnings enabled.
If you had done so, you would have caught things like these:
In function ‘read_meteo’:
test.c:51:16: warning: return from incompatible pointer type [-Wincompatible-pointer-types]
return arr;
^~~
error: ‘meteo_t {aka struct meteo_t}’ has no member named ‘preassure’;
did you mean ‘pressure’?
sscanf(line, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%s",
(arr[*len].meteo_id), (arr[*len].meteo_city_id), (arr[*len].tempt_max),
(arr[*len].tempt_min), (arr[*len].humidity), (arr[*len].preassure),
(arr[*len].date));
warning: comparison between pointer and integer
if (strcasecmp(date, meteo[i].date) == 0 && id == meteo[i].meteo_city_id) {
^~
warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
meteo_t *meteo = read_meteo("meteo.csv", &meteo_len);
^~~~~~~~~~
warning: passing argument 2 of ‘search_meteo_by_city_by_date’
makes integer from pointer without a cast [-Wint-conversion]
search_meteo_by_city_by_date(meteo, &meteo_len, local, id, date);
^~~~~~~~~~
note: expected ‘size_t {aka long unsigned int}’ but argument
is of type ‘size_t * {aka long unsigned int *}’
void search_meteo_by_city_by_date(meteo_t *meteo, size_t len,
^~~~~~~~~~~
const char *city, const int id, const char *date){
The not-so-right-after-all solution
Simply replace 152 with len. Apparently you already have an array index counter in there:
meteo_t *meteo = read_meteo("meteo.csv", &meteo_len);
if (meteo == NULL) {
printf("ERROR");
// YOU SHOULD ALSO EXIT IF YOU EVER ENTER HERE.
}
search_meteo_by_city_by_date(meteo, &meteo_len, cidade, id, date);
The above, as #user3629249 pointed out, is logically correct but formally incorrect because the parameter being passed is not the value (which is probably 152, so correct) but its address, which is almost surely NOT 152, and therefore wildly incorrect. And that's why when you apply this solution you get a crash.
If you had activated compiler warnings, this error wouldn't have been there, and if I had, I believe I would have given the right (but still not complete! Look at those problems above!) answer. Since neither of us used warnings, you and I both ended up being wrong. So: use compiler warnings.

Loss of values in array in struct after function execution

I am working on a c code that holds a structure that hosts some values which I call range.
My purpose is to use this so called range dynamically (holding different amount of data at every execution). I am now provisionally using the # define comp instead. This so called range gets updated every time I call my update_range though the use of s1 structure (and memory allocations).
What I found weird is that when I introduced a "show_range" function to output the actual values inside/outside the update function I realized that I loose the first two values.
Here is the code.
Any suggestions on that?
Thanks in advance!
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
#include <complex.h>
#define comp 1024
// struct holding a complex-valued range
struct range {
int dimensions; /* number of dimensions */
int* size; /* array holding number of points per dimension */
complex double* values; /* array holding complex valued */
int components; /* number of components that will change on any execution*/
};
// parameters to use in function
struct s1 {
int tag;
struct range* range;
};
int update_range(struct s1* arg);
int show_range(struct range* argrange, char* message);
int copy_range(struct range* in, struct range* out);
int main(void) {
int ret = 0;
struct s1 s1;
s1.tag = 0;
s1.range = malloc(sizeof(struct range));
update_range(&s1);
show_range(s1.range, "s1.range inside main function");
return ret;
}
////////////////////////////////////////////
int update_range(struct s1* arg) {
int ret = 0;
int i;
struct range range;
range.dimensions = 1;
range.size = malloc(range.dimensions * sizeof(int));
range.components = comp;
range.size[0] = range.components; // unidimensional case
range.values = malloc(range.components * sizeof(complex double));
for (i = 0; i < range.components; i++) {
range.values[i] = (i + 1) + I * (i + 1);
}
show_range(&range, "range inside update_range function");
arg->range->size =
malloc(range.dimensions * sizeof(int)); // size was unknown before
arg->range->values =
malloc(comp * sizeof(complex double)); // amount of values was unknown
copy_range(&range, arg->range);
show_range(arg->range, "arg->range inside update_range function");
if (range.size)
free(range.size);
range.size = NULL;
if (range.values)
free(range.values);
range.values = NULL;
return ret;
}
////////////////////////////////////////////
// Show parameters (10 first values)
int show_range(struct range* argrange, char* message) {
int ret = 0;
vint i;
printf(" ******************************\n");
printf(" range in %s \n", message);
printf(" arg.dimensions=%d \n", argrange->dimensions);
printf(" arg.size[0]=%d \n", argrange->size[0]);
printf(" argrange.components=%d \n", argrange->components);
printf(" first 10 {Re} values: \n");
for (i = 0; i < 10; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
printf("\n");
return ret;
}
////////////////////////////////////////////
// copy range
int copy_range(struct range* in, struct range* out) {
int ret = 0;
if (in == NULL) {
fprintf(stderr, "error: in points to NULL (%s:%d)\n", __FILE__,
__LINE__);
ret = -1;
goto cleanup;
}
if (out == NULL) {
fprintf(stderr, "error: out points to NULL (%s:%d)\n", __FILE__,
__LINE__);
ret = -1;
goto cleanup;
}
out->dimensions = in->dimensions;
out->size = in->size;
out->values = in->values;
out->components = in->components;
cleanup:
return ret;
}
Your copy_range function is broken, because it copy only pointer to size and values and not the memory. After you call free(range.size); and free(range.values); you are deleting mamory also from original object but without setting its pointers back to NULL.
After calling update_range, s1.range has non NULL pointers in size and values, but they are pointing to deleted memory.
You are experiencing undefined behaviour (UB) due to accessing freed memory. Your copy_range() function only does a shallow copy of the two pointer fields so when you run free(range->size) you make arg->range->size invalid.
You should make copy_range() a deep copy by allocating and copying the pointer contents like:
out->size = malloc(in->dimensions * sizeof(int));
memcpy(out->size, in->size, in->dimensions * sizeof(int));
out->values = malloc(in->components * sizeof(complex double));
memcpy(out->values , in->values, in->components * sizeof(complex double));
There are not 10 items to print, so the lines:
printf(" first 10 {Re} values: \n");
for (i = 0; i < 10; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
Will be printing from random memory.
a much better method would be:
printf(" first %d {Re} values: \n", min(argrange.components,10));
for (i = 0; i < argrange.components; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
The above is just one of many problems with the code.
I would suggest executing the code using a debugger to get the full story.
as it is, the code has some massive memory leaks due mostly
to overlaying malloc'd memory pointers.
for instance as in the following:
arg->range->size =
malloc(range.dimensions * sizeof(int)); // size was unknown before
arg->range->values =
malloc(comp * sizeof(complex double)); // amount of values was unknown

Forking with Pipes

I have tried to do fork() and piping in main and it works perfectly fine but when I try to implement it in a function for some reason I don't get any output, this is my code:
void cmd(int **pipefd,int count,int type, int last);
int main(int argc, char *argv[]) {
int pipefd[3][2];
int i, total_cmds = 3,count = 0;
int in = 1;
for(i = 0; i < total_cmds;i++){
pipe(pipefd[count++]);
cmd(pipefd,count,i,0);
}
/*Last Command*/
cmd(pipefd,count,i,1);
exit(EXIT_SUCCESS);
}
void cmd(int **pipefd,int count,int type, int last){
int child_pid,i,i2;
if ((child_pid = fork()) == 0) {
if(count == 1){
dup2(pipefd[count-1][1],1); /*first command*/
}
else if(last!=1){
dup2(pipefd[count - 2][0],0); /*middle commands*/
dup2(pipefd[count - 1][1],1);
}
else if(last == 1){
dup2(pipefd[count - 1][0],0); /*last command*/
}
for(i = 0; i < count;i++){/*close pipes*/
for(i2 = 0; i2 < 2;i2++){
close(pipefd[i][i2]);
}}
if(type == 0){
execlp("ls","ls","-al",NULL);
}
else if(type == 1){
execlp("grep","grep",".bak",NULL);
}
else if(type==2){
execl("/usr/bin/wc","wc",NULL);
}
else if(type ==3){
execl("/usr/bin/wc","wc","-l",NULL);
}
perror("exec");
exit(EXIT_FAILURE);
}
else if (child_pid < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
}
I checked the file descriptors and it is opening the right ones, not sure what the problem
could be..
Edit: I Fixed the problem but I'm having child processes, which way would be the best to wait for the child , while(wait(NULL)!=-1); but that hangs
The problem is that pipefd is not an int**, it's an int[3][2], so when you pass it to cmd, you get garbage. Your compiler should be giving you a warning on each call to cmd(), such as something like this:
warning: passing argument 1 of 'cmd' from incompatible pointer type
If not, turn up your warning level.
It's true that arrays decay into pointers to their first elements, so you can pass a 1-D array to a function expecting a pointer, but that's only true for the first dimension of arrays. In particular, a 2D array does not decay into a pointer to a pointer. It decays at the first level only, so pipefd can decay into the type int (*)[2], which is read as "pointer to array 2 of int"
So, the correct way to write cmd is this:
void cmd(int (*pipefd)[2],int count,int type, int last)

Resources