POSIX sem_wait() SIGABRT - c

I am working on a school project where we have to make a multithreaded web server. I am having a problem where when I call sem_wait on my semaphore (which should be initialized to 0 but already seems to be sem_post()ed to 1). I get a SIGABRT.
I am attaching my code below, and I put a comment on the line that is causing my problem. I've spent a few hours with the debugger with little luck.
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string>
#include <string.h>
#include <iostream>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <vector>
#include <semaphore.h>
#include <stdio.h>
#include <cstdlib>
#include <strings.h>
#define PORTNUM 7000
#define NUM_OF_THREADS 5
#define oops(msg) { perror(msg); exit(1);}
#define FCFS 0
#define SJF 1;
void bindAndListen();
void acceptConnection(int socket_file_descriptor);
void* dispatchJobs(void*);
void* replyToClient(void* pos);
//holds ids of worker threads
pthread_t threads[NUM_OF_THREADS];
//mutex variable for sleep_signal_cond
pthread_mutex_t sleep_signal_mutex[NUM_OF_THREADS];
//holds the condition variables to signal when the thread should be unblocked
pthread_cond_t sleep_signal_cond[NUM_OF_THREADS];
//mutex for accessing sleeping_thread_list
pthread_mutex_t sleeping_threads_mutex = PTHREAD_MUTEX_INITIALIZER;
//list of which threads are sleeping so they can be signaled and given a job
std::vector<bool> *sleeping_threads_list = new std::vector<bool>();
//number of threads ready for jobs
sem_t available_threads;
sem_t waiting_jobs;
//holds requests waiting to be given to one of the threads for execution
//request implemented as int[3] with int[0]== socket_descriptor int[1]== file_size int[2]== file_descriptor of requested file
//if file_size == 0 then HEAD request
std::vector<std::vector<int> >* jobs = new std::vector<std::vector<int> >();
pthread_mutex_t jobs_mutex = PTHREAD_MUTEX_INITIALIZER;
int main (int argc, char * const argv[]) {
//holds id for thread responsible for removing jobs from ready queue and assigning them to worker thread
pthread_t dispatcher_thread;
//initializes semaphores
if(sem_init(&available_threads, 0, NUM_OF_THREADS) != 0){
oops("Error Initializing Semaphore");
}
if(sem_init(&waiting_jobs, 0, 0) !=0){
oops("Error Initializing Semaphore");
}
//initializes condition variables and guarding mutexes
for(int i=0; i<NUM_OF_THREADS; i++){
pthread_cond_init(&sleep_signal_cond[i], NULL);
pthread_mutex_init(&sleep_signal_mutex[i], NULL);
}
if(pthread_create(&dispatcher_thread, NULL, dispatchJobs, (void*)NULL) !=0){
oops("Error Creating Distributer Thread");
}
for (int i=0; i<NUM_OF_THREADS; i++) {
pthread_mutex_lock(&sleeping_threads_mutex);
printf("before");
sleeping_threads_list->push_back(true);
printf("after");
pthread_mutex_unlock(&sleeping_threads_mutex);
}
printf("here");
for (int i=0; i<NUM_OF_THREADS; i++) {
//creates threads and stores ID in threads
if(pthread_create(&threads[i], NULL, replyToClient, (void*)i) !=0){
oops("Error Creating Thread");
}
}
/*
if(sem_init(&available_threads, 0, NUM_OF_THREADS) !=0){
oops("Error Initializing Semaphore");
}
if(sem_init(&waiting_jobs, 0, 0) !=0){ //this is the semaphore thats used in the sem_wait
oops("Error Initializing Semaphore");
}*/
bindAndListen();
}
//binds to socket and listens for connections
//being done by main thead
void bindAndListen(){
struct sockaddr_in saddr;
struct hostent *hp;
char hostname[256];
int sock_id, sock_fd;
gethostname(hostname, 256);
hp = gethostbyname(hostname);
bzero(&saddr, sizeof(saddr));
//errno = 0;
bcopy(hp->h_addr, &saddr.sin_addr, hp->h_length);
saddr.sin_family = AF_INET;
saddr.sin_port = htons(PORTNUM);
saddr.sin_addr.s_addr = INADDR_ANY;
sock_id = socket(AF_INET, SOCK_STREAM, 0);
if(sock_id == -1){
oops("socket");
printf("socket");
}
if(bind(sock_id, (const sockaddr*)&saddr, sizeof(saddr)) ==0){
if(listen(sock_id, 5) ==-1){
oops("listen");
}
//each time a new connection is accepted, get file info and push to ready queue
while(1){
int addrlen = sizeof(saddr);
sock_fd = accept(sock_id, (sockaddr*)&saddr, (socklen_t*)&addrlen);
if (sock_fd > 0) {
acceptConnection(sock_fd);
}else {
oops("Error Accepting Connection");
}
}
}else{
oops("there was an error binding to socket");
}
}// end of bindAndListen()
//accepts connection and gets file info of requested file
//being done by main thread
void acceptConnection(int sock_fd){
printf("**Server: A new client connected!");
//only using loop so on error we can break out on error
while(true){
//used to hold input from client
char* inputBuff = new char[BUFSIZ];
int slen = read(sock_fd, inputBuff, BUFSIZ);
//will sit on space between HEAD/GET and path
int pos1 = 0;
//will sit on space between path and HTTP version
int pos2 = 0;
//need duplicate ptr so we can manipulate one in the loop
char* buffPtr = inputBuff;
//parses client input breaks up query by spaces
for(int i=0; i<slen; i++){
if(*buffPtr == ' '){
if (pos1 == 0) {
pos1 = i;
}else {
pos2 = i;
break;
}
}
buffPtr++;
}
if((pos1 - pos2) >=0){
std::string str = "Invalid Query";
write(sock_fd, str.c_str(), strlen(str.c_str()));
break;
}
printf("slen length %d\n", slen);
std::string* method = new std::string(inputBuff, pos1);
printf("method length %lu\n",method->length());
//increment the ptr for buff to the starting pos of the path
inputBuff += ++pos1;
printf("pos2 - pos1 %d\n", (pos2 - pos1));
printf("pos1 = %d pos2 = %d\n", pos1, pos2);
std::string* path = new std::string(inputBuff, (pos2 - pos1));
printf("path length %lu\n", path->length());
printf("part1 %s\n", method->c_str());
printf("part2 %s\n", path->c_str());
//opens file requested by client
int fd = open(path->c_str(), O_RDONLY);
if(fd < 0){
std::string* error = new std::string("Error Opening File");
*error += *path + std::string(strerror(errno), strlen(strerror(errno)));
write(sock_fd, error->c_str(), strlen(error->c_str()));
break;
}
int file_size;
if(method->compare("GET") == 0){
//gets file info and puts the resulting struct in file_info
struct stat file_info;
if(fstat(fd, &file_info) !=0){
oops("Error getting file info");
}
file_size = file_info.st_size;
}else if(method->compare("HEAD")){
file_size = 0;
}else{
write(sock_fd, "Invalid Query", strlen("Invalid Query"));
break;
}
//job to be pushed to ready queue
std::vector<int> job;
job.push_back(sock_fd);
job.push_back(file_size);
job.push_back(fd);
//check mutex guarding the ready queue
pthread_mutex_lock(&jobs_mutex);
//push job to back of ready queue
jobs->push_back(job);
//unlock mutex guarding the ready queue
pthread_mutex_unlock(&jobs_mutex);
//increment number of jobs in ready queue
sem_post(&waiting_jobs);
} //end of while(true)
// we only end up here if there was an error
fflush(stdout);
close(sock_fd);
}// end of acceptConnection()
//routine run by dispather thread
void *dispatchJobs(void*){
while(true){
//wait for a thread to be available to execute a job
sem_wait(&available_threads);
//wait for a job to be waiting in the ready queue
sem_wait(&waiting_jobs); //this is the line thats crashing
//aquire lock to check which threads are waiting
pthread_mutex_lock(&sleeping_threads_mutex);
//go through list of threads to see which is waiting
for(int i=0; i<sleeping_threads_list->size(); i++){
if(sleeping_threads_list->at(i)){
//unlocks lock for access to list of waiting threads
pthread_mutex_unlock(&sleeping_threads_mutex);
//allows us access to the list of condition variables to signal the thread to resume execution
pthread_mutex_lock(&sleep_signal_mutex[i]);
pthread_cond_signal(&sleep_signal_cond[i]);
pthread_mutex_unlock(&sleep_signal_mutex[i]);
}
}
}//end of while(true)
}//end of dispatchJobs()
//sends file or metadata to client
//run by worker thread
//pos is position of condition variable that it waits to be signaled in the sleep_signal_cond[] array
void* replyToClient(void* pos){
int position = (long)pos;
while(true){
//waits for dispather thread to signal it
pthread_mutex_lock(&sleep_signal_mutex[position]);
pthread_cond_wait(&sleep_signal_cond[position], &sleep_signal_mutex[position]);
pthread_mutex_unlock(&sleep_signal_mutex[position]);
//lock mutex to get job to be executed
pthread_mutex_lock(&jobs_mutex);
std::vector<int> job = jobs->front();
//removes job from front of vector
jobs->erase(jobs->begin());
//releases mutex
pthread_mutex_unlock(&jobs_mutex);
//socket file descriptor, used for writing to socket
int sock_fd =job[0];
int file_size = job[1];
//file descriptor for requested job
int fd = job[2];
//holds output to be written to socket
char* outputBuffer = new char[BUFSIZ];
//GET request, send file
if(file_size !=0){
int readResult = 0;
while ((readResult = read(fd, outputBuffer, BUFSIZ)) > 0) {
if(write(sock_fd, outputBuffer, readResult) != readResult){
printf("We may have a write error");
}
}
if(readResult < 0){
oops("Error Reading File");
}
if(readResult == 0){
printf("finished sending file");
}
}else{ // HEAD request
}
//increment number of available threads
sem_post(&available_threads);
}
}// end of replyToClient()

Check again the whole logic of the code - it is possible to reach here:
pthread_mutex_lock(&jobs_mutex);
std::vector<int> job = jobs->front();
//removes job from front of vector
jobs->erase(jobs->begin());
//releases mutex
pthread_mutex_unlock(&jobs_mutex);
with jobs->size () == 0, in which case front() and erase() invoke undefined behavior, which may well result in the effects you observe.
Check whether your program still crashes after the following change:
//lock mutex to get job to be executed
pthread_mutex_lock(&jobs_mutex);
if (jobs->size () == 0)
{
pthread_mutex_unlock (&jobs_mutex);
continue;
}
std::vector<int> job = jobs->front();
//removes job from front of vector
jobs->erase(jobs->begin());
//releases mutex
pthread_mutex_unlock(&jobs_mutex);

I haven't used POSIX semaphores, but I believe this is what is happening. I'm only familiar with Linux kernel semaphores, and you don't mention your system. The init function's 3rd parameter probably sets the count variable. You set it to 0 (= busy but no other processes waiting). The wait function probably invokes down(), which begins by decreasing the count variable by 1: to -1, which means the semaphore you mean to use is locked now. There is nothing in your program to ever unlock it I believe (from browsing your code - it's pretty long), so you are in trouble. Try setting it to 1 in init. This might be all that is needed.

Related

Why does my program not wait when I call sem_wait?

Essentially, my program creates 3 threads. The "server" and 2 "workers." The workers are meant to sum the 3 digit positive integers in a 1000 line file (500 numbers per thread). After each worker has summed its part, the server prints each workers total. The only problem is my semaphores are not seeming to work.
Here is a version of my program:
// simple c program to simulate POSIX thread and semaphore
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
// define semaphores
sem_t s1;
FILE *file;
int sum1 = 0, sum2 = 0, num1 = 0, num2 = 0;
// file name
char fileName[10] = "data1.dat";
// server routine
void* server_routine()
{
printf("Server sent signal to worker thread 1\n");
printf("Server sent signal to worker thread 2\n");
sem_wait(&s1);
printf("Server recieved completion signal from worker thread 1\n");
sem_wait(&s1);
printf("Server recieved completion signal from worker thread 2\n\n");
// print the final results
printf("The sum of the first 500 numbers in the file is: %d\n", sum1);
printf("The sum of the last 500 numbers in the file is: %d\n\n", sum2);
pthread_exit(NULL);
}
// thread 1 reoutine
void* t1_routine()
{
printf("Thread 1 recieved signal from server\n");
file = fopen(fileName, "r");
for(int i = 0; i < 500; i++)
{
fscanf(file, "%d", &num1);
sum1 += num1;
}
printf("sum in thread 1: %d\n", sum1);
printf("Thread 1 sends completion signal to server\n");
sem_post(&s1);
pthread_exit(NULL);
}
// thread 2 routine
void* t2_routine()
{
printf("Thread 2 recieved signal from server\n");
file = fopen(fileName, "r");
fseek(file, 500 * 5, SEEK_SET);
for(int i = 0; i < 500; i++)
{
fscanf(file, "%d", &num2);
sum2 += num2;
}
printf("sum in thread 2: %d\n", sum2);
printf("Thread 2 sends completion signal to server\n");
sem_post(&s1);
pthread_exit(NULL);
}
// main function
int main(int argc, char *argv[])
{
// define threads
pthread_t server, t1, t2;
// initialize the semaphore
sem_init(&s1, 0, 0);
if(pthread_create(&server, NULL, &server_routine, NULL) != 0)
{
return 1;
}
if(pthread_create(&t1, NULL, &t1_routine, NULL) != 0)
{
return 2;
}
if(pthread_create(&t2, NULL, &t2_routine, NULL) != 0)
{
return 3;
}
if(pthread_join(server, NULL) != 0)
{
return 4;
}
if(pthread_join(t1, NULL) != 0)
{
return 5;
}
if(pthread_join(t2, NULL) != 0)
{
return 6;
}
// destroy semaphores
sem_close(&s1);
// exit thread
pthread_exit(NULL);
// end
return 0;
}
I've tested with less threads more semaphores as well, with non luck. I've tried different initial semaphore values. The only time I can get the correct output is when I manually wait with sleep(5); but that defeats the purpose of this project.
A few issues ...
Each client thread does its own/private fopen but FILE *file; is global so they overwrite each others values.
We need to make this variable function scoped so each thread has its own private pointer.
There are no fclose calls.
pthread_exit should not be done by the main thread. It is only for threads created with pthread_create.
Otherwise ...
Whichever thread does the fopen last will set the final value.
So, there is a race condition and the effect is the same as if the main thread (prior to pthread_create calls) had done a single fopen, defeating the purpose of each thread doing its own fopen.
Worse yet, a given thread may do the first fopen, then start with fscanf and have its file value changed when the second thread replaces the file value, so weird stuff happens to each thread because they are doing fseek/fscanf on the same FILE * instance.
Having the aforementioned fclose calls would have made the issue more evident.
Here is the refactored code. It is annotated:
// simple c program to simulate POSIX thread and semaphore
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
// define semaphores
sem_t s1;
// NOTE/BUG: each thread opens a different stream, so this must be function
// scoped
#if 0
FILE *file;
#endif
int sum1 = 0,
sum2 = 0,
num1 = 0,
num2 = 0;
// file name
char fileName[10] = "data1.dat";
// server routine
void *
server_routine()
{
printf("Server sent signal to worker thread 1\n");
printf("Server sent signal to worker thread 2\n");
sem_wait(&s1);
printf("Server recieved completion signal from worker thread 1\n");
sem_wait(&s1);
printf("Server recieved completion signal from worker thread 2\n\n");
// print the final results
printf("The sum of the first 500 numbers in the file is: %d\n", sum1);
printf("The sum of the last 500 numbers in the file is: %d\n\n", sum2);
pthread_exit(NULL);
}
// thread 1 reoutine
void *
t1_routine()
{
// NOTE/FIX: this must be function scoped (i.e. private to this thread)
#if 1
FILE *file;
#endif
printf("Thread 1 recieved signal from server\n");
file = fopen(fileName, "r");
for (int i = 0; i < 500; i++) {
fscanf(file, "%d", &num1);
sum1 += num1;
}
printf("sum in thread 1: %d\n", sum1);
printf("Thread 1 sends completion signal to server\n");
sem_post(&s1);
#if 1
fclose(file);
#endif
pthread_exit(NULL);
}
// thread 2 routine
void *
t2_routine()
{
// NOTE/FIX: this must be function scoped (i.e. private to this thread)
#if 1
FILE *file;
#endif
printf("Thread 2 recieved signal from server\n");
file = fopen(fileName, "r");
fseek(file, 500 * 5, SEEK_SET);
for (int i = 0; i < 500; i++) {
fscanf(file, "%d", &num2);
sum2 += num2;
}
printf("sum in thread 2: %d\n", sum2);
printf("Thread 2 sends completion signal to server\n");
sem_post(&s1);
#if 1
fclose(file);
#endif
pthread_exit(NULL);
}
// main function
int
main(int argc, char *argv[])
{
// define threads
pthread_t server, t1, t2;
// initialize the semaphore
sem_init(&s1, 0, 0);
if (pthread_create(&server, NULL, &server_routine, NULL) != 0) {
return 1;
}
if (pthread_create(&t1, NULL, &t1_routine, NULL) != 0) {
return 2;
}
if (pthread_create(&t2, NULL, &t2_routine, NULL) != 0) {
return 3;
}
if (pthread_join(server, NULL) != 0) {
return 4;
}
if (pthread_join(t1, NULL) != 0) {
return 5;
}
if (pthread_join(t2, NULL) != 0) {
return 6;
}
// destroy semaphores
sem_close(&s1);
// exit thread
// NOTE/BUG: only a subthread should do this
#if 0
pthread_exit(NULL);
#endif
// end
return 0;
}
In the code above, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k
UPDATE:
Thank you for the response Craig. I have implemented your suggestions to my own code but nothing seemed to change. I then decided to copy paste your updated code into a c file to test it out and I got the same result. It is as follows (in a separate comment since the output is too long): – 
Max
It's hard to compare results because we're using different datasets. I created a perl script to create some data.
Most important is that the sum reported by the given worker matches what the server sees for that worker task.
Then, if we know what each per thread section of the file should sum to, that is another matter.
The per line termination is critical (e.g.): CRLF vs LF (see below)
The actual order of worker sem_post and termination doesn't really matter. It can vary system to system or, even, invocation to invocation. What matters is that the server thread waits for N threads (i.e.) N sem_wait calls before printing any sums.
I've produced an updated version below.
Server does not "signal" a worker. The worker "signals" the server by doing sem_post and the server "receives" it by doing sem_wait
I've create a task/thread struct to hold the sums, thread IDs, etc.
I've generalized the code to allow N threads.
Added check of \n placement (i.e. line width). That is, under linux/POSIX a four digit number would be followed by LF (newline) and length would be 5. But, under windows, it would be CRLF (carriage return/newline) and length would be 6.
Added check of file size to ensure it is exactly the desired/expected length.
Some additional diagnostics.
Here is the updated code:
// simple c program to simulate POSIX thread and semaphore
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
#include <sys/stat.h>
// number of bytes per line
// 5: 4 digits + LF
// 6: 4 digits + CRLF
#ifndef LINEWID
#define LINEWID (4 + 1)
#endif
// number of items / task
#ifndef COUNT
#define COUNT 500
#endif
// define semaphores
sem_t s1;
#if 0
int sum1 = 0,
sum2 = 0,
num1 = 0,
num2 = 0;
#endif
// file name
#if 0
char fileName[10] = "data1.dat";
#else
const char *fileName = "data1.dat";
#endif
// task control
typedef struct {
pthread_t tid; // thread ID
int tno; // thread index/offset
int sum; // sum
} tsk_t;
#define TSKMAX 50
int tskmax; // actual number of tasks
tsk_t tsklist[TSKMAX]; // list of tasks
// loop through all task blocks
#define TSKFORALL \
tsk_t *tsk = &tsklist[0]; tsk < &tsklist[tskmax]; ++tsk
// server routine
void *
server_routine(void *vp)
{
// NOTE/BUG: server does _not_ signal worker
#if 0
printf("Server sent signal to worker thread 1\n");
printf("Server sent signal to worker thread 2\n");
#endif
for (TSKFORALL) {
printf("Server waiting ...\n");
sem_wait(&s1);
printf("Server complete ...\n");
}
// print the final results
for (TSKFORALL)
printf("The sum of task %d is %d\n",tsk->tno,tsk->sum);
return (void *) 0;
}
// thread 1 reoutine
void *
worker_routine(void *vp)
{
FILE *file;
tsk_t *tsk = vp;
printf("Thread %d running ...\n",tsk->tno);
file = fopen(fileName, "r");
fseek(file,tsk->tno * COUNT * LINEWID,SEEK_SET);
tsk->sum = 0;
int num1;
int first = -1;
int last = -1;
for (int i = 0; i < COUNT; i++) {
if (fscanf(file, "%d", &num1) != 1) {
printf("Thread %d fscan error\n",tsk->tno);
break;
}
if (i == 0)
first = num1;
if (i == (COUNT - 1))
last = num1;
tsk->sum += num1;
}
printf("sum in thread %d: %d (first %d, last %d)\n",
tsk->tno, tsk->sum, first, last);
sem_post(&s1);
#if 1
fclose(file);
#endif
return (void *) 0;
}
// main function
int
main(int argc, char **argv)
{
--argc;
++argv;
setlinebuf(stdout);
setlinebuf(stderr);
if (argc != 1)
tskmax = 2;
else
tskmax = atoi(*argv);
if (tskmax > TSKMAX)
tskmax = TSKMAX;
// define threads
pthread_t server;
printf("main: %d tasks\n",tskmax);
printf("main: %d count\n",COUNT);
FILE *file = fopen(fileName,"r");
if (file == NULL) {
printf("main: fopen failure\n");
exit(96);
}
// check alignment
char chr;
fseek(file,LINEWID - 1,0);
fread(&chr,1,1,file);
if (chr != '\n') {
printf("main: newline mismatch -- chr=%2.2X\n",chr);
exit(97);
}
// get the file size
struct stat st;
if (fstat(fileno(file),&st) < 0) {
printf("main: fstat fault\n");
exit(97);
}
// ensure the file has the correct size
off_t size = tskmax * LINEWID * COUNT;
if (st.st_size != size)
printf("main: wrong file size -- st_size=%llu size=%llu\n",
(unsigned long long) st.st_size,
(unsigned long long) size);
fclose(file);
// initialize the semaphore
sem_init(&s1, 0, 0);
// set the offsets
int tno = 0;
for (TSKFORALL, ++tno)
tsk->tno = tno;
if (pthread_create(&server, NULL, &server_routine, NULL) != 0)
return 98;
for (TSKFORALL) {
if (pthread_create(&tsk->tid,NULL,worker_routine,tsk) != 0)
return 1 + tsk->tno;
}
if (pthread_join(server, NULL) != 0) {
return 99;
}
for (TSKFORALL) {
if (pthread_join(tsk->tid, NULL) != 0) {
return 5;
}
}
// destroy semaphores
sem_close(&s1);
// end
return 0;
}
Here is the perl script output that I used to generate the data:
number of tasks 2
element count per task 500
line separater 0A
section 0 sum 124750
section 1 sum 125250
Here is the program output:
main: 2 tasks
Server waiting ...
Thread 0 running ...
Thread 1 running ...
sum in thread 1: 125250 (first 1, last 500)
sum in thread 0: 124750 (first 0, last 499)
Server complete ...
Server waiting ...
Server complete ...
The sum of task 0 is 124750
The sum of task 1 is 125250
Here is the perl script:
#!/usr/bin/perl
# gendata -- generate data
#
# arguments:
# 1 - number of tasks (DEFAULT: 2)
# 2 - number of items / task (DEFAULT: 500)
# 3 - line separater (DEFAULT: \n)
master(#ARGV);
exit(0);
# master -- master control
sub master
{
my(#argv) = #_;
$tskmax = shift(#argv);
$tskmax //= 2;
printf(STDERR "number of tasks %d\n",$tskmax);
$count = shift(#argv);
$count //= 500;
printf(STDERR "element count per task %d\n",$count);
$sep = shift(#argv);
$sep //= "\n";
printf(STDERR "line separater");
foreach $chr (split(//,$sep)) {
$hex = ord($chr);
printf(STDERR " %2.2X",$hex);
}
printf(STDERR "\n");
for ($itsk = 0; $itsk < $tskmax; ++$itsk) {
$val = $itsk;
$sum = 0;
for ($lno = 1; $lno <= $count; ++$lno, ++$val) {
printf("%4d%s",$val,$sep);
$sum += $val;
}
printf(STDERR "section %d sum %d\n",$itsk,$sum);
}
}

Is this the correct way to use pthread?

I am trying to create an HTTP server using multi-threading. main() hands off the client_sock from accept() to one of the worker threads. If no worker threads are available, it waits until one is. I am restricted to not being able to call accept() within the worker threads. Here is a portion of my code so far. Some questions I have are:
Do I need to use 2 pthread mutex and condition variables as I do right now?
Do I need to use pthread lock or unlock at all in these cases?
If I wanted to add a mutex lock when files are being created on the server, would I have to create another mutex variable or would one of the existing ones work?
#include <iostream>
#include <err.h>
#include <fcntl.h>
#include <netdb.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <getopt.h>
#include <pthread.h>
#define SIZE 1024
struct shared_data
{
int redundancy;
int client_sock;
int working_threads;
int dispatch_ready;
pthread_mutex_t* dispatch_mutex;
pthread_mutex_t* worker_mutex;
pthread_cond_t* dispatch_cond;
pthread_cond_t* worker_cond;
};
void* receiveAndSend(void* obj)
{
struct shared_data* data = (struct shared_data*) obj;
int bytes;
char buff[SIZE + 1];
while(1)
{
while(!data->dispatch_ready)
{
pthread_cond_wait(data->dispatch_cond, data->dispatch_mutex);
}
data->dispatch_ready = 0;
data->working_threads++;
client_sock = data->client_sock;
bytes = recv(client_sock, buff, SIZE, 0);
// do work
data->working_threads--;
pthread_cond_signal(data->worker_cond);
}
}
int main(int argc, char* argv[])
{
if(argc < 2 || argc > 6)
{
char msg[] = "Error: invalid arg amount\n";
write(STDERR_FILENO, msg, strlen(msg));
exit(1);
}
char* addr = NULL;
unsigned short port = 80;
int num_threads = 4;
int redundancy = 0;
char opt;
while((opt = getopt(argc, argv, "N:r")) != -1)
{
if(opt == 'N')
{
num_threads = atoi(optarg);
if(num_threads < 1)
{
char msg[] = "Error: invalid input for -N argument\n";
write(STDERR_FILENO, msg, strlen(msg));
exit(1);
}
}
else if(opt == 'r')
{
redundancy = 1;
}
else
{
// error (getopt automatically sends an error message)
return 1;
}
}
// non-option arguments are always the last indexes of argv, no matter how they are written in the terminal
// optind is the next index of argv after all options
if(optind < argc)
{
addr = argv[optind];
optind++;
}
if(optind < argc)
{
port = atoi(argv[optind]);
}
if(addr == NULL)
{
char msg[] = "Error: no address specified\n";
write(STDERR_FILENO, msg, strlen(msg));
exit(1);
}
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = getaddr(addr);
serv_addr.sin_port = htons(port);
int serv_sock = socket(AF_INET, SOCK_STREAM, 0);
if(serv_sock < 0)
{
err(1, "socket()");
}
if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
{
err(1, "bind()");
}
if(listen(serv_sock, 500) < 0)
{
err(1, "listen()");
}
// Connecting with a client
struct sockaddr client_addr;
socklen_t client_addrlen;
pthread_mutex_t dispatch_mutex;
pthread_mutex_init(&dispatch_mutex, NULL);
pthread_mutex_t worker_mutex;
pthread_mutex_init(&worker_mutex, NULL);
pthread_cond_t dispatch_cond;
pthread_cond_init(&dispatch_cond, NULL);
pthread_cond_t worker_cond;
pthread_cond_init(&worker_cond, NULL);
struct shared_data data;
data.redundancy = redundancy;
data.dispatch_ready = 0;
data.working_threads = 0;
data.dispatch_mutex = &dispatch_mutex;
data.worker_mutex = &worker_mutex;
data.dispatch_cond = &dispatch_cond;
data.worker_cond = &worker_cond;
pthread_t* threads = new pthread_t[num_threads];
for (int i = 0; i < num_threads; i++)
{
pthread_create(&threads[i], NULL, receiveAndSend, &data);
}
while(1)
{
data.client_sock = accept(serv_sock, &client_addr, &client_addrlen);
while(data.working_threads == num_threads)
{
pthread_cond_wait(data.worker_cond, data.worker_mutex);
}
data.dispatch_ready = 1;
pthread_cond_signal(data.dispatch_cond);
}
return 0;
}
There are many very basic bugs in your program, which pretty clearly demonstrate that you don't understand locks and condition variables (or appropriate use of pointers).
A lock protects some shared data. You have exactly one shared data item, therefore you should need exactly one lock (mutex) to protect it.
A condition variable indicates that some condition is true. Reasonable conditions for your use case would be worker_available and work_available. (Naming your condition variables dispatch_cond and worker_cond does not help clarity.)
A condition variable is always associated with a mutex, but you don't need two separate mutexes just because you have two condition variables.
On to the bugs.
This code is obviously buggy:
while(1)
{
while(!data->dispatch_ready)
{
pthread_cond_wait(data->dispatch_cond, data->dispatch_mutex);
}
From man pthread_cond_wait:
atomically release mutex and cause the calling thread to block on the condition variable cond
How can this thread release a mutex if it never acquired it?
Also, how can this thread read data->dispatch_ready (shared with other threads) without acquiring a mutex?
This code:
struct shared_data data;
data.redundancy = redundancy;
data.dispatch_ready = 0;
data.working_threads = 0;
data.dispatch_mutex = &dispatch_mutex;
data.worker_mutex = &worker_mutex;
data.dispatch_cond = &dispatch_cond;
data.worker_cond = &worker_cond;
isn't buggy, but has unnecessary indirection. You could make dispatch_mutex and condition variables be part of shared_data, like so:
struct shared_data
{
int redundancy;
int client_sock;
int working_threads;
int dispatch_ready;
pthread_mutex_t dispatch_mutex;
pthread_mutex_t worker_mutex;
pthread_cond_t dispatch_cond;
pthread_cond_t worker_cond;
};
And here is the most subtle bug I noticed:
data.client_sock = accept(serv_sock, &client_addr, &client_addrlen);
...
data.dispatch_ready = 1;
pthread_cond_signal(data.dispatch_cond);
Here, you will wake up at least one of the threads waiting for dispatch_cond, but may wake up more than one. If more than one thread is awoken, they all will proceed to recv on the same client_sock with potentially disastrous results.
Update:
How do I fix this.
Probably the best and most performant way to fix this is to have a queue of "work items" (using e.g. a double-linked list with head and tail pointers), protected by a lock.
Main thread would add elements at the tail (while holding a lock), and signal "not empty" condition variable.
Worker threads would remove head element (while holding a lock).
Worker threads would block on "not empty" condition variable when queue is empty.
Main thread may continue adding elements when queue is full (all workers are busy), or it may block waiting for a worker to become available, or it can return "429 too many requests" to the client.

How to block and open Clients with Semaphore? Semaphore problem

I have a multiclient Server Socket and I want to block the acces for other Clients, when sending "BEG" to the Server. To open the other Clients again, the Client has to send "END" to the Server. While other Clients are blocked off, they only can use "quit" to exit the Server and if they use conditions() they fall asleep.
So other Clients are blocked for the function conditions() if one process used "BEG", but the process himself has still acces to the function.
If I compile my Code, the Server is running, everything is fine but the Mutexe doesn't work.
The Code is going into the if statement of "BEG" and the Mutex should be locked, but other Clients aren't blocked off.
If I connect a second Client, the Client gets kicked if I use conditions().
My question is, why does the mutex not work for other Clients or in generell? How to check if the Mutex is working?
Edit:
Now my Semaphore doesn't block other processes
Edit 2: I found a way, not the best but one. Now some clients are getting kicked from the Server after using one condition().
main.c:
int state = 0;
int beg() {
state = 1;
return 0;
}
int end() {
state = 0;
return 0;
}
int main() {
int pid, t;
char *eingabe, *inputBuffer[BUFSIZE];
char delimiter[] = "\n ";
int rfd = erstelleSocket();
int cfd;
semaphor semID1 = semGET();
semaphor semID2 = semGET2();
marker[0] = 1;
t = semctl(semID1, 1, SETALL, marker);
if (t == -1) {
fprintf(stderr, "Error with marker\n");
}
t = semctl(semID2, 1, SETALL, marker);
if (t == -1) {
fprintf(stderr, "Error with marker\n");
}
while(1){
cfd = accept(rfd, (struct sockaddr *) &client, &client_len);
if (cfd < 0) {
close(cfd);
fprintf(stderr, "connection failed\n");
break;
}
pid = fork();
if (pid < 0) {
fprintf(stderr, "Error in new process creation\n");
}
if (pid == 0) {
bzero(input, sizeof(input));
bytes_read = read(cfd, input, BUFSIZE);
strncat(input, " ", strlen(" "));
input[strcspn(input, "\r\n")] = 0;
while (bytes_read > 0) {
eingabe = strtok(input, delimiter);
int i = 0;
while (eingabe != NULL) {
inputBuffer[i++] = eingabe;
eingabe = strtok(NULL, delimiter);
}
if (strncmp("quit", inputBuffer[0], 4) == 0) {
close(cfd);
break;
}
if (state != 1) {
down(semID2, 0); //down is a function with semop()
}
down(semID1, 0);
conditions(inputBuffer[0],
inputBuffer[1],
inputBuffer[2],
cfd, semID1, shmID);
up(semID1, 0);
if (state != 1) {
up(semID2, 0); //up is a function with semop()
}
bzero(input, sizeof(input));
bytes_read = read(cfd, input, BUFSIZE);
strncat(input, " ", strlen(" "));
input[strcspn(input, "\r\n")] = 0;
close(rfd);
}
}
close(cfd);
}
close(rfd);
}
my condition function:
void conditions(char *eingabehalter1,
char *eingabehalter2,
char *eingabehalter3,
int cfd, int shmID) {
if (strncmp("PUT", eingabehalter1, 3) == 0) {
put(eingabehalter2, eingabehalter3, cfd, shmID);
} else if (strncmp("GET", eingabehalter1, 3) == 0) {
get(eingabehalter2, cfd, shmID);
} else if (strncmp("DEL", eingabehalter1, 3) == 0) {
del(eingabehalter2, cfd, shmID);
} else if (strncmp("BEG", eingabehalter1, 3) == 0) {
beg();
} else if (strncmp("END", eingabehalter1, 3) == 0) {
end();
} else {
write(cfd, "cmd_nonexistent\n", strlen("cmd_nonexistent\n"));
}
}
createSocket.c:
int rfd; // Rendevouz-Descriptor
rfd = socket(AF_INET, SOCK_STREAM, 0);
int option = 1;
setsockopt(rfd,SOL_SOCKET, SO_REUSEADDR, (const void *) &option, sizeof(int));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
int brt = bind(rfd, (struct sockaddr *) &server, sizeof(server));
int lrt = listen(rfd, 5);
return rfd;
}
main.h:
#include "shmmemory.h"
#include "semaphoren.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <netinet/in.h>
#define PORT 5678
struct sockaddr_in server;
struct sockaddr_in client;
socklen_t client_len;
char input[BUFSIZE];
int bytes_read;
int erstelleSocket();
void conditions(char *eingabehalter1,
char *eingabehalter2,
char *eingabehalter3,
int cfd, int shmID);
int beg();
int end();
unsigned short marker[2];
Your approach cannot work because you're trying to combine fork with threads. fork creates a copy of the parent's address space for each child process, which means that each child process has its own copy of the mutex object. Process-shared mutexes are possible in POSIX, with special attributes, but I suspect even those don't work with fork; they have to be placed in shared memory.
Have you considered creating threads with pthread_create for the service loop? Or else you can implement this entirely using fork (no pthread material). The children can use POSIX named semaphores (sem_open, et al) or possibly, dare I say it, System V IPC.
Also, don't use strtok in multithreaded code, and clearing memory to zero was standardized in 1989's ANSI C as memset(pointer, 0, size). Since that was 31 years ago, it's okay to lay bzero to rest.
The way you initialize the semaphores is wrong for your use case. From the man page of sem_init():
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
If pshared has the value 0, then the semaphore is shared between the
threads of a process, and should be located at some address that is
visible to all threads (e.g., a global variable, or a variable
allocated dynamically on the heap).
If pshared is nonzero, then the semaphore is shared between
processes, and should be located in a region of shared memory
Based on the above explanations from the man page, the things you need change are:
Semaphore declaration
Since you are using semaphores between processes, you need to declare the variable as shared. You can do that via mmap() to create unnamed UNIX semaphore as follows:
sem_t* sem_var = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0)
if (sem_var == MAP_FAILED) // Shared memory creation failed.
goto handle_shm_fail;
Semaphore initialization
Since you are using POSIX semaphores, to make your child use the same semaphores, pshared is set to 1 indicating semaphore is shared between processes.
if (sem_init(sem_var, 1, 1) != 0) // Semaphore initialization failed.
goto handle_sem_fail;
NOTE: In your code sem_var is of type sem_t, now it is a pointer to sem_t. Accordingly, you need to update your code.

Run mutex, but fails to create multiple threads

I am trying to simulate a server/client socket communication, and using threads for each client and then use mutex to lock and unlock those clients.
Mutex is working fine, even if I open another terminal and run the client script, it gets blocked till server unlocks it, but for some bad coding reason, this second client gets the same ID from the first client.
So, I want to create a new thread every time I run a new client. But I think that this "fork" is being the problem, for some reason...
int counter = 0;
int i = 0;
int j = 0;
void* operacoes (void*);
pthread_mutex_t mutexA = PTHREAD_MUTEX_INITIALIZER;
pthread_t thread_id [10];
int var;
int jo = 0;
int t = 0;
int main()
{
int sock_fd, sock_len, sock_novo, sock_novo_len,num;
struct sockaddr_un sock_ser, sock_cli;
char msg[100];
sock_fd = socket(AF_UNIX, SOCK_STREAM,0);
if(sock_fd<0)
{
printf("ERROR\n");
exit(0);
}
unlink("socket.unix.teste");
bzero((char*)&sock_ser, sizeof(sock_ser));
sock_ser.sun_family = AF_UNIX;
strcpy(sock_ser.sun_path,"socket.unix.teste");
sock_len = strlen(sock_ser.sun_path) +sizeof(sock_ser.sun_family);
if(bind(sock_fd,(struct sockaddr*)&sock_ser,sock_len)<0)
{
printf("ERROR\n");
exit(0);
}
listen(sock_fd,5);
for(;;)
{
sock_novo_len = sizeof(sock_cli);
sock_novo = accept(sock_fd, (struct sockaddr*)&sock_cli,&sock_novo_len);
if(fork() == 0)
{
close(sock_fd);
num = atoi(msg);
counter++;
for (i = jo; i<counter; i++)
{
pthread_create (&thread_id[i], NULL, operacoes, (void *)num);
jo++;
}
for (j = t; j<counter; j++)
{
pthread_join(thread_id[j], NULL);;
t++;
}
exit(0);
}
close(sock_novo);
}
return 0;
}
void* operacoes (void *arg)
{
if(arg == 1)
{
int id = pthread_self();
printf("Thread nummber: %d \n", id);
pthread_mutex_lock (&mutexA);
printf("Locked\n");
sleep(10);
pthread_mutex_unlock (&mutexA);
printf("Unlocked\n");
}
return 0;
}
On client side, I only send a single variable 'msg'.
How could I solve it? I tried to use those two variables 'jo' and 't', but every new client I create, it reads the whole code, and it gets back to 0 so I cant get next phthread_create's vector position.
Assuming I understand correctly what you want to achieve:
Create a unix domain socket and listen for incoming connections
Treat each connection in parallel
Have one global mutex being locked/unlocked during treatment of the connections
try this:
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
pthread_mutex_t mutexA = PTHREAD_MUTEX_INITIALIZER;
struct oarg_t {
int con_socket;
};
void* operacoes (void *arg)
{
struct oarg_t* oarg = arg;
int id = pthread_self();
printf("Thread number: %d \n", id);
pthread_mutex_lock (&mutexA);
printf("Locked\n");
sleep(10);
pthread_mutex_unlock (&mutexA);
printf("Unlocked\n");
close(oarg->con_socket);
free(oarg);
return 0;
}
int main()
{
const char* domain_name = "socket_unix.teste";
int i = 0;
int j = 0;
int sock_fd;
sock_fd = socket(AF_UNIX, SOCK_STREAM,0);
if(sock_fd<0) goto error;
unlink(domain_name);
struct sockaddr_un sock_ser = {
.sun_family = AF_UNIX,
};
strncpy(sock_ser.sun_path, domain_name, sizeof(sock_ser.sun_path));
if(0 != bind(sock_fd, (struct sockaddr*) &sock_ser, sizeof(sock_ser)))
goto error;
listen(sock_fd,5);
size_t counter = 0;
while(1) {
struct sockaddr_un sock_cli = {0};
int sock_len = sizeof(sock_cli);
int sock_novo =
accept(sock_fd, (struct sockaddr*)&sock_cli, &sock_len);
if(0 > sock_novo) {
printf("Error accepting:% s\n", strerror(errno));
continue;
}
printf("Connection no %zu\n", counter++);
struct oarg_t* oarg = calloc(1, sizeof(struct oarg_t));
oarg->con_socket = sock_novo;
pthread_t id = 0;
pthread_create (&id, NULL, operacoes, oarg);
}
return EXIT_SUCCESS;
error:
printf("ERROR: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}

Segfault on Server after Multithreading in C

So I'm trying to code a multi-threading server. I've spent an enormous time on the internet figuring out the correct way to do this and the answer as always seems to be it depends. Whenever I execute my code, the client successfully connects, and executes but when the thread terminates and returns to the while loop the whole program segfaults.
I probably could use a good spanking on a few other things as well such as my usage of global variables. The entirety of code is below, sorry for the inconsistent space/tabbing.
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include <signal.h>
#include <math.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
/* ---------------------------------------------------------------------
This is a basic whiteboard server. You can query it, append to it and
clear in it. It understands both encrypted and unencrypted data.
--------------------------------------------------------------------- */
struct whiteboard {
int line;
char type;
int bytes;
char string[1024];
} *Server;
int serverSize, threadcount, id[5];
bool debug = true;
struct whiteboard *Server;
pthread_mutex_t mutex;
pthread_t thread[5];
/* -------------------------------------------
function: sigint_handler
Opens a file "whiteboard.all" in writemode
and writes all white board information in
command mode.
------------------------------------------- */
void sigint_handler(int sig)
{
if (debug) printf("\nInduced SIGINT.\n");
FILE *fp;
fp=fopen("whiteboard.all","w");
int x=0;
for (x;x<serverSize;x++) // Loop Responsible for iterating all the whiteboard entries.
{
if (debug) printf("#%d%c%d\n%s\n",Server[x].line,Server[x].type,Server[x].bytes,Server[x].string);
fprintf(fp,"#%d%c%d\n%s\n",Server[x].line,Server[x].type,Server[x].bytes,Server[x].string);
}
if (debug) printf("All values stored.\n");
free(Server); // Free dynamically allocated memory
exit(1);
}
/* -------------------------------------------
function: processMessage
Parses '!' messages into their parts -
returns struct in response.
------------------------------------------- */
struct whiteboard processMessage(char * message)
{
int lineNumber, numBytes;
char stringType, entry[1028];
if (debug) printf("Update Statement!\n");
// Read line sent by Socket
sscanf(message,"%*c%d%c%d\n%[^\n]s",&lineNumber,&stringType,&numBytes,entry);
if (debug) printf("Processed: Line: %d, Text: %s\n",lineNumber,entry);
// Parse information into local Struct
struct whiteboard Server;
Server.line = lineNumber;
Server.type = stringType;
Server.bytes = numBytes;
strcpy(Server.string,entry);
// If there is no bytes, give nothing
if (numBytes == 0)
{
strcpy(Server.string,"");
}
return Server;
}
/* -------------------------------------------
function: handleEverything
Determines type of message recieved and
process and parses accordingly.
------------------------------------------- */
char * handleEverything(char* message, struct whiteboard *Server, char* newMessage)
{
bool updateFlag = false, queryFlag = false;
// If message is an Entry
if (message[0] == '#')
{
if (debug) printf("Triggered Entry!\n");
// Create Temporary Struct
struct whiteboard messageReturn;
messageReturn = processMessage(message);
// Store Temporary Struct in Correct Heap Struct
Server[messageReturn.line] = messageReturn;
sprintf(newMessage,"!%d%c%d\n%s\n",messageReturn.line, messageReturn.type, messageReturn.bytes, messageReturn.string);
return newMessage;
}
// If message is a query
if (message[0] == '?')
{
if (debug) printf("Triggered Query!\n");
int x;
queryFlag = true;
sscanf(message,"%*c%d",&x); // Parse Query
if (x > serverSize) // Check if Query out of Range
{
strcpy(newMessage,"ERROR: Query out of Range.\n");
return newMessage;
}
sprintf(newMessage,"!%d%c%d\n%s\n",Server[x].line,Server[x].type,Server[x].bytes,Server[x].string);
if (debug) printf("newMessage as of handleEverything:%s\n",newMessage);
return newMessage;
}
}
/* -------------------------------------------
function: readFile
If argument -f given, read file
process and parse into heap memory.
------------------------------------------- */
void readFile(char * filename)
{
FILE *fp;
fp=fopen(filename,"r");
int line, bytes, count = 0, totalSize = 0;
char type, check, string[1028], individualLine[1028];
// Loop to determine size of file. **I know this is sloppy.
while (fgets(individualLine, sizeof(individualLine), fp))
{
totalSize++;
}
// Each line shoud have totalSize - 2 (to account for 0)
// (answer) / 2 to account for string line and instruction.
totalSize = (totalSize - 2) / 2;
serverSize = totalSize+1;
if (debug) printf("Total Size is: %d\n",serverSize);
// Open and Allocate Memory
fp=fopen(filename,"r");
if (debug) printf("File Mode Calloc Initialize\n");
Server = calloc(serverSize+2, sizeof(*Server));
// Write to Heap Loop
while (fgets(individualLine, sizeof(individualLine), fp)) {
if (individualLine[0] == '#') // Case of Header Line
{
sscanf(individualLine,"%c%d%c%d",&check,&line,&type,&bytes);
if (debug) printf("Count: %d, Check:%c, Line:%d, Type: %c, Bytes:%d \n",count,check,line,type,bytes);
Server[count].line = line;
Server[count].type = type;
Server[count].bytes = bytes;
count++;
}
else
{
// For case of no data
if (individualLine[0] == '\n')
{
strcpy(string,"");
}
// Then scan data line
sscanf(individualLine,"%[^\n]s",string);
if (debug) printf("String: %s\n",string);
strcpy(Server[count-1].string,string);
}
}
return;
}
void *threadFunction(int snew)
{
char tempmessage[1024], message[2048];
// Compile and Send Server Message
strcpy(tempmessage, "CMPUT379 Whiteboard Server v0\n");
send(snew, tempmessage, sizeof(tempmessage), 0);
// Recieve Message
char n = recv(snew, message, sizeof(message), 0);
pthread_mutex_lock(&mutex);
if (debug) printf("Attempt to Malloc for newMessage\n");
char * newMessage = malloc(1024 * sizeof(char));
if (debug) printf("goto: handleEverything\n");
newMessage = handleEverything(message, Server, newMessage);
if (debug) printf("returnMessage:%s\n",newMessage);
strcpy(message,newMessage);
free(newMessage);
pthread_mutex_unlock(&mutex);
if (debug) printf("message = %s\n", message);
send(snew, message, sizeof(message), 0);
printf("End of threadFunction\n");
return;
}
/* -------------------------------------------
function: main
Function Body of Server
------------------------------------------- */
int main(int argc, char * argv[])
{
int sock, fromlength, outnum, i, socketNumber, snew;
bool cleanMode;
// Initialize Signal Handling
struct sigaction act;
act.sa_handler = sigint_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, 0);
// For correct number of arguments.
if (argc == 4)
{
// If "-n" parameter (cleanMode)
if (strcmp(argv[2], "-n") == 0)
{
// Get size + 1
cleanMode = true;
sscanf(argv[3],"%d",&serverSize);
serverSize += 1;
if (debug) printf("== Clean Mode Properly Initiated == \n");
if (debug) printf("serverSize: %d\n",serverSize);
if (debug) printf("Clean Mode Calloc\n");
Server = calloc(serverSize, sizeof(*Server));
int i = 0;
for (i; i < serverSize; i++) // Initialize allocated Memory
{
Server[i].line = i;
Server[i].type = 'p';
Server[i].bytes = 0;
strcpy(Server[i].string,"");
}
}
// If "-f" parameter (filemode)
else if (strcmp(argv[2], "-f") == 0)
{
// Read File
cleanMode = false;
readFile(argv[3]);
if (debug) printf("== Statefile Mode Properly Initiated == \n");
if (debug) printf("serverSize: %d\n",serverSize);
}
// Otherwise incorrect parameter.
else
{
printf("Incorrect Argument. \n");
printf("Usage: wbs279 pornumber {-n number | -f statefile}\n");
exit(1);
}
sscanf(argv[1],"%d",&socketNumber);
}
// Send Error for Incorrect Number of Arguments
if (argc != 4)
{
printf("Error: Incorrect Number of Input Arguments.\n");
printf("Usage: wbs279 portnumber {-n number | -f statefile}\n");
exit(1);
}
// == Do socket stuff ==
char tempmessage[1024], message[2048];
struct sockaddr_in master, from;
if (debug) printf("Assrt Socket\n");
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
perror ("Server: cannot open master socket");
exit (1);
}
master.sin_family = AF_INET;
master.sin_addr.s_addr = INADDR_ANY;
master.sin_port = htons (socketNumber);
if (bind (sock, (struct sockaddr*) &master, sizeof (master)))
{
perror ("Server: cannot bind master socket");
exit (1);
}
// == Done socket stuff ==
listen (sock, 5);
int threadNumber = 0;
while(1)
{
printf("But what about now.\n");
if (debug) printf("-- Wait for Input --\n");
printf("Enie, ");
fromlength = sizeof (from);
printf("Meanie, ");
snew = accept (sock, (struct sockaddr*) & from, & fromlength);
printf("Miney, ");
if (snew < 0)
{
perror ("Server: accept failed");
exit (1);
}
printf("Moe\n");
pthread_create(&thread[threadNumber],NULL,threadFunction(snew), &id[threadNumber]);
//printf("Can I join?!\n");
//pthread_join(thread[0],NULL);
//printf("Joined?!\n");
threadNumber++;
close (snew);
}
}
I'm also curious as to how exactly to let multiple clients use the server at once. Is how I've allocated the whiteboard structure data appropriate for this process?
I'm very sorry if these don't make any sense.
You seem to somehow expect this:
pthread_create(&thread[threadNumber],NULL,threadFunction(snew), &id[threadNumber]);
/* ... */
close (snew);
To make sense, while it clearly doesn't.
Instead of starting a thread that runs threadFunction, passing it snew, you call the thread function and pass the return value to pthread_create(), which will interpret it as a function pointer. This will break, especially considering that the thread function incorrectly ends with:
return;
This shouldn't compile, since it's declared to return void *.
Also assuming you managed to start the thread, passing it snew to use as its socket: then you immediately close that socket, causing any reference to it from the thread to be invalid!
Please note that pthread_create() does not block and wait for the thread to exit, that would be kind of ... pointless. It starts off the new thread to run in parallel with the main thread, so of course you can't yank the carpet away from under it.
This signal handler is completely unsafe:
void sigint_handler(int sig)
{
if (debug) printf("\nInduced SIGINT.\n");
FILE *fp;
fp=fopen("whiteboard.all","w");
int x=0;
for (x;x<serverSize;x++) // Loop Responsible for iterating all the whiteboard entries.
{
if (debug) printf("#%d%c%d\n%s\n",Server[x].line,Server[x].type,Server[x].bytes,Server[x].string);
fprintf(fp,"#%d%c%d\n%s\n",Server[x].line,Server[x].type,Server[x].bytes,Server[x].string);
}
if (debug) printf("All values stored.\n");
free(Server); // Free dynamically allocated memory
exit(1);
}
Per 2.4.3 Signal Actions of the POSIX standard (emphasis added):
The following table defines a set of functions that shall be
async-signal-safe. Therefore, applications can call them, without
restriction, from signal-catching functions. ...
[list of async-signal-safe functions]
Any function not in the above table may be unsafe with respect to signals. Implementations may make other interfaces
async-signal-safe. In the presence of signals, all functions defined
by this volume of POSIX.1-2008 shall behave as defined when called
from or interrupted by a signal-catching function, with the exception
that when a signal interrupts an unsafe function or equivalent
(such as the processing equivalent to exit() performed after a return
from the initial call to main()) and the signal-catching function
calls an unsafe function, the behavior is undefined. Additional
exceptions are specified in the descriptions of individual functions
such as longjmp().
Your signal handler invokes undefined behavior.

Resources