This program is supposed to take a file name and argument(s) and create a process that executes the code while outputting the result to the terminal (which I don't know why that isn't working either).
I have found that the seg fault is coming from my attempt to free the argvNew array of strings
#include <iostream>
using namespace std;
#include <unistd.h>
#include <sys/wait.h>
main(int argc, char **argv){
int pid;
int i;
char *argvNew[argc-1];
do{
//Check for failure
if ((pid = fork()) < 0) {
cerr << "Fork error\n";
exit(1);
}
//Check if parent
else if (pid == 0) {
/* child process */
//Add arguments to new array
for(i = 0; i < argc-2; i++){
argvNew[i] = argv[i+1];
}
argvNew[argc-2] = NULL;
if (execvp(argv[1], argvNew) < 0) {
cerr << "Execve error\n";
exit(1);
}
}
else {
/* parent */
waitpid(pid, NULL, 0);/* wait for the child to finish */
//Free argvNew
for(i = 0; i < argc-1;i++){
free(argvNew[i]);
}
free(argvNew);
}
//if we're need to create a new list of args in the future put it here
}while(!argc);
}
test input: ./myProgram /bin/ls -l
argvNew is automaticlly allocated, which means that the resources held by it are released automagiclly when it goes out of scope. You only need to free dynamicly allocated arrays:
char a[50]; // the [50] means automatic allocation
// ...
// no need to free
char* a = malloc(50); // dynamic allocation
// ...
// need to free later, or memory leak
free(a);
for(i = 0; i < argc-1;i++){
free(argvNew[i]);
}
//This next call is identical to free(argvNew[0]), probably where you're
//segfaulting, since you're freeing something twice
free(argvNew);
Note that you don't need to call free(), since argvNew[] contains pointers that do not point to new/malloc'ed data, but rather to the values of the argv array, which are managed by the parent process and should not be explicitly free()'ed by you
Related
I'm trying to run a C++ program I've been writing from my school's Unix Command-Line based server. The program is supposed to use commands like pipe() and fork() to calculate an integer in the child process and send it to the parent process through a pipe. The problem I've come across is when I try to run the program after compiling it, nothing happens at all except for a '0' is inserted before the prompt. I don't completely understand forking and piping so I'll post the entire program in case the problem is in my use of those commands. There are probably errors because I haven't been able to successfully run it yet. Here is my code:
#include <cstdlib>
#include <iostream>
#include <string>
#include <array>
#include <cmath>
#include <unistd.h>
using namespace std;
// Return bool for whether an int is prime or not
bool primeChecker(int num)
{
bool prime = true;
for (int i = 2; i <= num / 2; ++i)
{
if (num%i == 0)
{
prime = false;
break;
}
}
return prime;
}
int main(int argc, char *argv[])
{
int *array;
array = new int[argc - 1]; // dynamically allocated array (size is number of parameters)
int fd[2];
int count = 0; // counts number of primes already found
int num = 1; // sent to primeChecker
int k = 1; // index for argv
int addRes = 0;
// Creates a pair of file descriptors (int that represents a file), pointing to a pipe inode,
// and places them in the array pointed to. fd[0] is for reading, fd[1] is for writing
pipe(fd);
while (k < argc)
{
if (primeChecker(num)) // if the current number is prime,
{
count++; // increment the prime number count
if (count == (stoi(argv[k]))) // if the count reaches one of the arguments...
{
array[k - 1] = num; // store prime number
k++; // increment the array of arguments
}
}
num++;
}
pid_t pid;
pid = fork();
if (pid < 0) // Error occurred
{
cout << "Fork failed.";
return 0;
}
else if(pid == 0) // Child process
{
for (int i = 0; i < (argc-1); i++)
{
// Close read descriptor (not used)
close(fd[0]);
// Write data
write(fd[1], &addRes, sizeof(addRes)); /* write(fd, writebuffer, max write lvl) */
// Close write descriptor
close(fd[1]);
}
}
else // Parent process
{
// Wait for child to finish
wait(0);
// Close write descriptor (not used)
close(fd[1]);
// Read data
read(fd[0], &addRes, sizeof(addRes));
cout << addRes;
// Close read descriptor
close(fd[0]);
}
return 0;
}
Here is what I'm seeing in the command window (including the prompt) when I try to compile and run my program:
~/cs3270j/Prog2$ g++ -o prog2.exe prog2.cpp
~/cs3270j/Prog2$ ./prog2.exe
0~/cs3270j/Prog2$
and nothing happens. I've tried different naming variations as well as running it from 'a.out' with no success.
tl;dr after compiling and attempting to execute my program, the Unix command prompt simply adds a 0 to the beginning of the prompt and does nothing else.
Any help that anybody could give me would be very much appreciated as I can't find any information whatsoever about a '0' appearing before the prompt.
Your program is doing exactly what you're telling it to do! You feed addRes into the pipe, and then print it out. addRes is initialized to 0 and never changed. In your child, you want to pass num instead. Also, you may want to print out a new line as well ('\n').
You never write anything to the pipe; writing is once per each command line argument, and ./prog2.exe does not supply any, so the loop never executes
If you passed one argument, you would write addRes; you never change addRes, so you'd get 0 in the parent
If you passed multiple arguments, you'd write one addRes then close the channel. This is not too bad since you never read more than one addRes anyway.
You print out your addRes (which is unchanged from its initialisation int addRes = 0) without a newline, which makes the next prompt stick right next to it (using cout << addRes << endl would print out a newline, making it prettier)
I have been working on this project for a while. The purpose is to make a functioning shell that can do pretty much all the shell commands (except cd). It does almost everything I want it to do, except for a couple things. The first is that when I put an '&' to signify background processing, it does it, but then doesn't print another myshell> line. I can still input something, but the myshell> never shows up, no matter where I put another cout<<"myshell> ";.
Another issue is if I press enter, making myString empty, many times, it crashes the program with a seg fault. Also after I do the '&' background processing and press enter to get the myshell> to come back up, it prints one myshell> but then seg faults on the next hit of enter. I'm sorry if I didn't explain this well, but it is really driving me crazy. Please let me know if you have any suggestions.
#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <cstdio>
#include <sys/wait.h>
#include <stdio.h>
/*Function that parses the command the user inputs.
It takes myArgv and myString as inputs.
It returns the value of exitcond, which is used to see if the user wants to exit or not.
Also, this is where myString is tokenized using strok()*/
int parseCommand(char *myArgv[10], char myString[255])
{
int exitcond=0;
if((strcmp(myArgv[0], "exit") == 0)||(strcmp(myArgv[0], "quit")==0))
{
exitcond = 1;
return exitcond;
}
int i;
char *token;
token = strtok(myString," ");
i=0;
while (token != NULL)
{
myArgv[i] = token;
token = strtok(NULL," ");
i++;
}
/*
* Set the last entry our new argv to a null char
* (see man execvp to understand why).
*/
myArgv[i] = '\0';
return exitcond;
}
/*Function that gets the command from the user and sees if they want
background processing or not (presence of '&').
It takes inputs of choose and myString. choose is the variable for
whether background processing is necessary or not, while myString is
an empty character array.
It outputs the value of the choose variable for lter use.*/
int getCommand(int choose, char myString[255])
{
int i;
choose=0;
fgets(myString, 256, stdin);
if (myString[0]=='\0')
{
choose=0;
return choose;
}
for (i=0; myString[i]; i++)
{
if (myString[i]== '&')
{
choose=1;
myString[i]=' ';
}
if (myString[i] == '\n')
{
myString[i] = '\0';
}
}
return choose;
}
/*Main function where all the calling of other functions and processes
is done. This is where the user enters and exits the shell also. All
usage of fork, pid, waitpid and execvp is done here.*/
int main()
{
using namespace std;
int exitCondition=0, i=0, status;
char myString[255];
char *token, *myArgv[10];
pid_t pid, waiting;
int bg=0;
while (!exitCondition)
{
/* print a prompt and allow the user to enter a stream of characters */
cout << "myshell> ";
bg=0;
int choose=0;
bg=getCommand(choose,myString);
exitCondition=parseCommand(myArgv,myString);
if(exitCondition==1)
{
cout<<"Thank you for using my shell.\n";
}
else {
/* while (myString[0]=='\0')
{
cout<<"myshell> ";
bg=getCommand(choose,myString);
}*/
/* The user has a command, so spawn it in a child process */
pid = fork();
if (pid == -1)
{
/* to understand why this is here, see man 2 fork */
cout << "A problem arose, the shell failed to spawn a child process" << endl;
return(1);
}
else if (pid == 0)
{
// Child process
execvp(myArgv[0],myArgv);
cout << "Bad command or file name, please try again!\n" << endl;
return 0;
} else {
/* This makes sure that the spawned process is run in the foreground,
because the user did not choose background */
if(bg==0)
{
waitpid(pid,NULL,0);
}
}
}
}
return 0;
}
Okay, you had three bugs, one of which caused the segfault. Of the others, one would put a garbage argument in the array passed to execvp and the other would leak zombie processes for background jobs.
I've corrected the code and annotated it with where the bugs were along with the fixes [please pardon the gratuitous style cleanup]:
#include <cstdio>
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define AVCOUNT 100
#define STRBUFLEN 2000
/*Function that parses the command the user inputs.
It takes myArgv and myString as inputs.
It returns the value of exitcond, which is used to see if the user wants to
exit or not.
Also, this is where myString is tokenized using strok()*/
int
parseCommand(char **myArgv, char *myString)
{
char *token;
char *bp;
int exitcond = 0;
int i;
// NOTE/BUG: original check for exit/quit was here -- at this point
// myArgv is undefined (hence the segfault)
// NOTE/BUG: your original loop -- at the end i was one beyond where it
// should have been so that when myArgv gets passed to execvp it would
// have an undefined value at the end
#if 0
token = strtok(myString, " ");
i = 0;
while (token != NULL) {
myArgv[i] = token;
token = strtok(NULL, " ");
i++;
}
#endif
// NOTE/BUGFIX: here is the corrected loop
i = 0;
bp = myString;
while (1) {
token = strtok(bp, " ");
bp = NULL;
if (token == NULL)
break;
myArgv[i++] = token;
}
/*
* Set the last entry our new argv to a null pointer
* (see man execvp to understand why).
*/
// NOTE/BUG: with your code, i was one too high here
myArgv[i] = NULL;
// NOTE/BUGFIX: moved exit/quit check to here now that myArgv is valid
token = myArgv[0];
if (token != NULL) {
if ((strcmp(token, "exit") == 0) || (strcmp(token, "quit") == 0))
exitcond = 1;
}
return exitcond;
}
/*Function that gets the command from the user and sees if they want
background processing or not (presence of '&').
It takes inputs of choose and myString. choose is the variable for
whether background processing is necessary or not, while myString is
an empty character array.
It outputs the value of the choose variable for lter use.*/
int
getCommand(int choose, char *myString)
{
int i;
choose = 0;
fgets(myString, STRBUFLEN, stdin);
if (myString[0] == '\0') {
choose = 0;
return choose;
}
for (i = 0; myString[i]; i++) {
if (myString[i] == '&') {
choose = 1;
myString[i] = ' ';
}
if (myString[i] == '\n') {
myString[i] = '\0';
break;
}
}
return choose;
}
/*Main function where all the calling of other functions and processes
is done. This is where the user enters and exits the shell also. All
usage of fork, pid, waitpid and execvp is done here.*/
int
main()
{
using namespace std;
int exitCondition = 0;
int status;
char myString[STRBUFLEN];
char *myArgv[AVCOUNT];
pid_t pid;
int bg = 0;
while (!exitCondition) {
// NOTE/BUGFIX: without this, any background process that completed
// would become a zombie because it was never waited for [again]
// reap any finished background jobs
while (1) {
pid = waitpid(0,&status,WNOHANG);
if (pid < 0)
break;
}
/* print a prompt and allow the user to enter a stream of characters */
cout << "myshell> ";
bg = 0;
int choose = 0;
bg = getCommand(choose, myString);
exitCondition = parseCommand(myArgv, myString);
if (exitCondition == 1) {
cout << "Thank you for using my shell.\n";
break;
}
/* while (myString[0]=='\0') { cout<<"myshell> "; bg=getCommand(choose,myString); } */
/* The user has a command, so spawn it in a child process */
pid = fork();
if (pid == -1) {
/* to understand why this is here, see man 2 fork */
cout << "A problem arose, the shell failed to spawn a child process" << endl;
return 1;
}
if (pid == 0) {
// Child process
execvp(myArgv[0], myArgv);
cout << "Bad command or file name, please try again!\n" << endl;
return 1;
}
/* This makes sure that the spawned process is run in the
foreground, because the user did not choose background */
if (bg == 0)
waitpid(pid, &status, 0);
}
return 0;
}
I created a program that tests carchive. I wanted to see how fast it took to save a million data points:
#include "stdafx.h"
#include "TestData.h"
#include <iostream>
#include <vector>
using namespace std;
void pause() {
cin.clear();
cout << endl << "Press any key to continue...";
cin.ignore();
}
int _tmain(int argc, _TCHAR* argv[])
{
int numOfPoint = 1000000;
printf("Starting test...\n\n");
vector<TestData>* dataPoints = new vector<TestData>();
printf("Creating %i points...\n", numOfPoint);
for (int i = 0; i < numOfPoint; i++)
{
TestData* dataPoint = new TestData();
dataPoints->push_back(*dataPoint);
}
printf("Finished creating points.\n\n");
printf("Creating archive...\n");
CFile* pFile = new CFile();
CFileException e;
TCHAR* fileName = _T("foo.dat");
ASSERT(pFile != NULL);
if (!pFile->Open(fileName, CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive, &e))
{
return -1;
}
bool bReading = false;
CArchive* pArchive = NULL;
try
{
pFile->SeekToBegin();
UINT uMode = (bReading ? CArchive::load : CArchive::store);
pArchive = new CArchive(pFile, uMode);
ASSERT(pArchive != NULL);
}
catch (CException* pException)
{
return -2;
}
printf("Finished creating archive.\n\n");
//SERIALIZING DATA
printf("Serializing data...\n");
for (int i = 0; i < dataPoints->size(); i++)
{
dataPoints->at(i).serialize(pArchive);
}
printf("Finished serializing data.\n\n");
printf("Cleaning up...\n");
pArchive->Close();
delete pArchive;
pFile->Close();
delete pFile;
printf("Finished cleaning up.\n\n");
printf("Test Complete.\n");
pause();
return 0;
}
When I run this code, it takes some time to create the data points, but then it runs through the rest of the code almost instantly. However, I then have to wait about 4 minutes for the application to actually finish running. I would assume the application would wait hang at the serializing data portion just like it did during the creation of the data points.
So my question is about how this actually work. Does carchive do its thing on a separate thread and allow the rest of the code to execute?
I can provide more information if necessary.
If you want to create a vector with a million elements that are all default-initialized you just just use this version of the constructor
vector<TestData> dataPoints{numOfPoint};
You should stop newing everything, let RAII handle the cleanup for you.
Also, know that push_back requires a resize of your vector if it's capacity isn't large enough, so if you start with an empty vector, and know how big it is going to be at the end, you can use reserve ahead of time.
vector<TestData> dataPoints;
dataPoints.reserve(numOfPoint);
for (int i = 0; i < numOfPoint; i++)
{
dataPoints->push_back(TestData{});
}
I have almost completed an homework assignment where I am required to use pthreads. I have figured out the pthreads. The only problem I have left is figuring out how to pass multiple arguments to threads through pthread_create().
I need to pass two chars to the thread. I have to cast them to (*void) to use with pthread_create(). I can pass them, but I can't figure out how to get the values from *parameter in the function.
void *my_function(void *parameter) {
/* ATTEMPT 1 - DOESN'T WORK */
//char* arguments[2];
//arguments = (char * [2]) parameter;
/*Error message:
error: ISO C++ forbids casting to an array type char* [2] [-fpermissive]
error: incompatible types in assignment of char** to char*[2]
*/
/* ATTEMPT 2 - DOESN'T WORK */
//char *my_data = (char *)parameter;
//my_data is blank when I try to use cout to check it's values
/* What I need to do is get those two chars from the array and print them out as part of this thread function */
pthread_exit(NULL);
}
int main(int argc, char **argv) {
char duration = '5'; //in reality, this value is taken from argv but I am leaving that out for brevity
pthread_t threads[3];
for(int i=0; i < 3; i++){
char thread_args[2] = {i, duration};
//create thread with arguments passed in
int results = pthread_create(&threads[i], NULL, my_function, (void *) &thread_args);
//testing for pthread error
if (results){
printf("ERROR; return code from pthread_create() is %d\n", results);
exit(-1);
}
}
/* Wait for all threads to complete */
for (int j=0; j < num_threads; j++) { // https://computing.llnl.gov/tutorials/pthreads/
pthread_join(threads[j], NULL);
}
/* some information prints here that is unrelated to my problem (the date, time, etc) */
pthread_exit(NULL);
}
I was able to pass one value through with no problem. Any suggestions?
The closest existing question I could find was this but I still am having no luck: Converting from void* to char ** in C
Thank you!
Note that within this loop:
for(int i=0; i < 3; i++){
char thread_args[2] = {i, duration};
int results = pthread_create(&threads[i], NULL, my_function, (void *)
...
}
thread_args is a local array with automatic storage duration, lifetime of which is tied to each iteration so there is a chance that the memory where you store these arguments might be freed before the thread will access it, which would lead to undefined behavior in that case.
Much better approach would be to create a structure, that you would use to pass the data to this thread:
typedef struct {
char duration;
int num;
} ThreadData;
Then your code could look like this:
void *my_function(void *parameter) {
// retrieve and print the thread data:
ThreadData* td = (ThreadData*) parameter;
printf("num = %d, duration = %c\n", td->num, td->duration);
delete td;
return NULL;
}
int main(int argc, char **argv) {
char duration = '5';
pthread_t threads[3];
for (int i = 0; i < 3; i++) {
// create structure that will be passed to thread:
ThreadData* td = new ThreadData;
td->duration = duration;
td->num = i;
//create thread with arguments passed in:
int ret = pthread_create(&threads[i], NULL, my_function, (void *) td);
//testing for pthread error:
if (ret) {
printf("ERROR; return code from pthread_create() is %d\n", ret);
exit(-1);
}
}
// wait for all threads to complete:
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
exit(0);
}
Also note that to end thread's execution it is better to use return than pthread_exit since with return it is guaranteed that variables within thread's routine will be destroyed and stack will be unwound. For more information see return() versus pthread_exit() in pthread start functions
I am writing this code, which basically takes an argument specifying how many child threads I want, forks to get them, and then prints all the pids which are stored in an array.
This would be fine if only the parent would need the PIDs, but I also need the child to get their IDS (pcid). I copy and pasted some code from the net (which I didn't really understand), so I'm not sure why it's not working.
I get a segmentation error after the first PID prints.
What's wrong here?
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/shm.h>
#include <sys/ipc.h>
int main(int argc, char *argv[])
{
if(argc < 2) {
printf("ERROR: No arguments fed.\n");
exit(-1);
}
int amount = atoi(argv[1]);
int i;
int pid = 1;
int pcid = 0;
key_t key;
int shmid;
int *arr[amount];
key = ftok("thread1.c",'R');
shmid = shmget(key, 1024, 0644 | IPC_CREAT);
for(i = 0; i < amount; i++)
{
if(pid != 0)
{
pid = fork();
}
*arr = shmat(shmid, (void *) 0, 0);
if(pid != 0)
{
*arr[i] = pid;
}
else
{
pcid = *arr[i];
break;
}
}
if(pid != 0)
{
printf("Printing PID Array:\n");
for(i =0; i < amount; i++)
{
printf("%d\n", *arr[i]);
}
}
else
{
printf("My PID: %d\n",pcid);
}
}
you are using an array of pointers. And in line *arr = shmat(shmid, (void *) 0, 0) you assigned the shared memory access point to the first element of array. Now when you are using *arr[i] = pid it will go to the array i+1 element where an unknown address stays and you try to put a value there. so you got segmentation fault.