0
votes

So, I haven't used much C in quite some time, and was never very comfortable with malloc. I don't know if that is the source of the problem, but I'm getting a segmentation fault, and if anyone here sees anything obvious that might be wrong with it, it would save me a lot of trouble finding it, because I'm not even sure where to start.

information provided to main on launch re: thread limit, account limit, output file. possible input

TRANS [acct id 1] [amount] [acct id 2] [amount] etc...

CHECK [acct id]

END

not much output, most information is provided to output file.

If this code is particularly difficult to understand or follow, let me know and I'll try to explain.

Edit: All memory errors from valgrind were resulting from calls to strtok(). I've messed with this, and still can't seem to fix it. How do I use strtok() from a scanned variable without causing these errors?

appserver.c

-main program

#include<stdlib.h>
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<string.h>
#include "Bank.c"
#include "appserver.h"




struct account *accounts=NULL;
pthread_t *threads=NULL;
char *threadstatus=NULL;
int done=0;
char busywait=0;
FILE * f;

int main(int argc, char **argv){
    int threadcount, banksize;
    char* outputpath;
    if(argc<4)
    {
        threadcount=1;
        banksize=100;
        outputpath="output.txt";
    }
    else
    {
        char *tstr=argv[1];
        char *sstr=argv[2];
        outputpath=argv[3];
        threadcount=(int) strtol(tstr, NULL, 10);
        banksize=(int) strtol(sstr, NULL, 10);
    }




    int reqID=0;
    struct request *req1, *req2;
    req1 = (struct request *) malloc( sizeof(struct request) );
    char * in;
    char *s;

    initialize_status(threadcount);
    threads = (pthread_t *) calloc( threadcount, sizeof(pthread_t) );
    initialize_accounts(banksize);
    initialize_mutex(banksize);
    f=fopen(outputpath,"w");
    int stringsize=1000;

    int threadindex=0;
    int i;
    while(1)
    {
        
        printf("> ");
        getline(&in, &stringsize, stdin);
        s=strtok(in," ");
        if( strcmp( (const char *) s, "CHECK") == 0 )
        {
            req2 = (struct request *) malloc( sizeof(struct request) );
            reqID++;
            req1->type = 'b';
            s=strtok(NULL," ");
            req1->balanceID = (int) strtol( s, NULL, 10);
            req1->next = req2;
            req1->requestID = reqID;
            threadindex=nextthread(threadcount);
            if(threadindex<0)
            {
                busywait=1;
                while(busywait==1)
                {
                    //do nothing, waiting for a thread to finish
                }
                threadindex=nextthread(threadcount);
            }
            req1->thread=threadindex;
            pthread_create(&threads[threadindex], NULL, (void *)&workthread, &req1);
            req1=req2;
        }
        else if( strcmp( (const char *) s, "TRANS") == 0 )
        {
            req2 = (struct request *) malloc( sizeof(struct request) );
            i=0;
            reqID++;
            req1->type = 't';
            while(s!=NULL&&i<10)
            {
                s = strtok(NULL," ");
                req1->transIDs[i] = (int) strtol( s, NULL, 10);
                if((s = strtok(NULL," "))==NULL)
                {
                     printf("Bad input: \n");
                     break;
                }
                req1->transvals[i] = (int) strtol( s, NULL, 10);
                i++;
            }
            req1->next = req2;
            req1->requestID = reqID;
            threadindex=nextthread(threadcount);
            if(threadindex<0)
            {
                busywait=1;
                while(busywait==1)
                {
                    //do nothing
                }
                threadindex=nextthread(threadcount);
            }
            req1->thread=threadindex;
            pthread_create(&threads[threadindex], NULL, (void *)&workthread, &req1);
            req1=req2;
        }
        else if( strcmp( (const char *) s, "END") == 0)
        {
            req1->type = 'e';
            threadindex=nextthread(threadcount);
            if(threadindex<0)
            {
                busywait=1;
                while(busywait==1)
                {
                    //do nothing
                }
                threadindex=nextthread(threadcount);
            }
            req1->thread=threadindex;
            pthread_create(&threads[threadindex], NULL, (void *)&workthread, &req1);
            for( i = 0; i < threadcount; i++)
                pthread_join( threads[i], NULL);
            free(accounts);
            free(threads);
            break;
        }
        else
        {
            printf("Try again\n");
        }
        free(in);
    }
    return 0;
}

void *workthread(struct request *data)
{
    threadstatus[data->thread]='b';
    int value;
    int i, balance;
    printf("< ID %d\n",data->requestID);
    while(1)
    {
        if(data->type == 't')
        {   
            int transamt[10]={0,0,0,0,0,0,0,0,0,0};
            int values[10]={0,0,0,0,0,0,0,0,0,0};
            for(i=0;i<10;i++)
            {
                if(!data->transIDs[i])
                    break;
                transamt[i]=data->transvals[i];
                value=read_account(data->transIDs[i]);
                if((values[i]=value+transamt[i])<0)
                {
                    busywait = 0;
                    threadstatus[data->thread]='a';
                    fprintf(f,"%d ISF %d\n",data->requestID,data->transIDs[i]);
                    return;
                }
            }
            if(translock(data->transIDs) == 1)
            {
                int ID;
                for(i=0;i<10;i++)
                {
                    ID=data->transIDs[i];
                    accounts[ID-1].value=values[i];
                    write_account(data->transIDs[i],values[i]);
                }
            }
            transunlock(data->transIDs);
            busywait=0;
            threadstatus[data->thread]='a';
            fprintf(f,"%d OK\n",data->requestID);
            return;
        }
        else if(data->type == 'b')
        {
            int balance=read_account(data->balanceID);
            fprintf(f,"%d BAL %d\n",data->requestID,balance);
            threadstatus[data->thread]='a';
            busywait=0;
            return;
        }


        else if(data->type == 'e')
        {
            done=1;
            return;
        }
    }
}

int transunlock(int ids[])
{
    struct account *current;
    int i=0;
    for(i=9;i>=0;i--)
    {
        current=&accounts[ids[i]-1];
        if(ids[i]<1)
            continue;
        pthread_mutex_unlock(&current->lock); //unlock previous account
    }
    return;
}

int translock(int ids[])
{
    struct account *current;
    int i=0;
    for(i=0;i<10;i++)
    {
        current=&accounts[ids[i]-1];
        if(ids[i]<1||pthread_mutex_trylock(&current->lock)!=0) //if lock attempt fails
        {
            while(--i>=0)
            {
                pthread_mutex_unlock(&current->lock); //unlock previous account
            }
            return 0;
        }
        current++;
    }
    return 1;
}

int initialize_mutex(int n)
{
    accounts=(struct account *) malloc(sizeof(struct account) * n);
    if(accounts==NULL)
        return 0;
    int i;
    for(i=0;i<n;i++)
    {
        accounts[i].value=0;
    }
    return 1;
}

int initialize_status(int n)
{
    threadstatus = (char *) malloc( sizeof(char) * n );
    int k;
    for(k=0;k<n;k++)
    {
        threadstatus[k]='a';
    }
}

int nextthread(int n)
{
    int i;
    for(i=0;i<n;i++)
    {
        if(threadstatus[i]=='a')
            return i;
    }
    return -1;
}

appserver.h

#include<pthread.h>

struct account{
    pthread_mutex_t lock;
    int value;
};

struct request{
    char type; //'b' for balance check, 't' for transaction, 'e' for exit
    int transIDs[10];
    int transvals[10];
    int balanceID;
    struct request *next;
    int requestID;
    int thread;
};


void *workthread(struct request *data);
int transunlock(int ids[]);
int translock(int ids[]);
int initialize_mutex(int n);
int initialize_status(int n);
int nextthread(int n);

Bank.c

/**  Do not modify this file  **/

#include "Bank.h"
#include <stdlib.h>


int *BANK_accounts; //Array for storing account values

/*
 *  Intialize back accounts
 *  Input:  int n - Number of bank accounts
 *  Return:  1 if succeeded, 0 if error
 */
int initialize_accounts( int n )
{
    BANK_accounts = (int *) malloc(sizeof(int) * n);
    if(BANK_accounts == NULL) return 0;

    int i;
    for( i = 0; i < n; i++)
    {
        BANK_accounts[i] = 0;
    }
    return 1;
}

/*
 *  Read a bank account
 *  Input:  int ID - Id of bank account to read
 *  Return:  Value of bank account ID
 */
int read_account( int ID )
{
    usleep( 100000 );
    return BANK_accounts[ID - 1];
}

/*
 *  Write value to bank account
 *  Input:  int ID - Id of bank account to write to
 *  Input:  int value - value to write to account
 */
void write_account( int ID, int value)
{
    usleep( 100000 );
    BANK_accounts[ID - 1] = value;
}

Bank.h

/**  Do not modify this file  **/

/*
 *  These functions do not provide any error checking.
 *  If an invalid input is supplied the behavior is
 *  undefined.
 */

/*
 *  Intialize n bank accounts with IDs from 1 to n and values of 0.
 *  Input:  int n - Number of bank accounts, must be larger than 0
 *  Return:  1 if succeeded, 0 if error
 */
int initialize_accounts( int n );

/*
 *  Read a bank account
 *  Input:  int ID - Id of bank account to read
 *  Return:  Value of bank account ID
 */
int read_account( int ID );

/*
 *  Write value to bank account
 *  Input:  int ID - Id of bank account to write to
 *  Input:  int value - value to write to account
 */
void write_account( int ID, int value);

Like I said earlier, all errors on valgrind related to strtok() calls, as follows:

Conditional jump or move depends on uninitialised value(s)

Use of uninitialised value of size 8

Invalid read of size 1

Process terminating with default action of signal 11 (SIGSEGV)

1
Run your code under valgrind. That will tell you if you're doing anything fishy with regard to memory.dbush
This is just... a problem. All that busywait thread-micromanagement stuff. It's asking for trouble:(Martin James
How else should I go about it? If all the threads in the server are being used, I want to be able to have some way of knowing when one of the threads finishes. I know I could join all the threads, but that just forces me to wait for every single thread to finish, is there a way around this?Sam O.
I think you may have a problem with the struct initialization. You have created a linked list of sorts, and are not initializing the nodes before using them. ( referring to struct request with member struct request *next; )ryyker
It's also worth mentioning that I just did some messing around with valgrind, and pretty much every single error it returned was related to calls to strtok()---------- Conditional jump or move depends on uninitialised value(s)------ Use of uninitialised value of size 8------ Invalid read of size 1------ Process terminating with default action of signal 11 (SIGSEGV)------ all these errors in response to input "TRANS 1 10". I've messed with the calls to strtok with no luck.Sam O.

1 Answers

1
votes

In main() you wrote:

char * in;
...
while(1)
{
    printf("> ");
    scanf("%s",&in);

I think scanf() doesn't call malloc() for you.