code:
local void*
s_accept_connections(tmpsock)
void* tmpsock;
{
int32_t newfd;
int32_t tmp;
SOCKADDR_IN newsockaddr;
pthread_t id;
Connection* newconn;
const char *s;
char **splited;
int i;
StringVec *p;
StringVec* next;
Socket* sock;
tmp = sizeof(newsockaddr);
p = NULL;
next = NULL;
sock = (Socket *)tmpsock;
if (!sock)
return 0;
while (true){
newfd = accept(sock->fd,(SOCKADDR *)&newsockaddr,&tmp);
if (newfd <0){
if (check_error_async()){
pthread_mutex_lock(&g_socket_mutex);
#ifdef _WIN32
Sleep(1000);
#else
sleep(1);
#endif
pthread_mutex_unlock(&g_socket_mutex);
continue;
}
}else{
newconn = (Connection *)MyMalloc(sizeof(*newconn));
newconn->fd = newfd;
newconn->addr = newsockaddr;
s = (const char *)inet_ntoa(newsockaddr.sin_addr);
p = split_string(s,".");
if (p != NULL){
splited = (char **)MyMalloc(sizeof(*splited) + 12);
i = 0;
for (; p != NULL; p = next){
if (p && p->next){
next = p->next;
}else{ break; }
splited[i] = p->value;
i++;
}
newconn->ip = swap_uint32_t((uint32_t)(atoi(splited[0])) + (atoi(splited[1]) << 8) + (atoi(splited[2]) << 16) + (atoi(splited[3]) << 24));
MyFree((char *)splited);
}else{
newconn->ip = 0;
}
newconn->closed = false;
newconn->state = 0;
newconn->state |= S_NEED_LOGIN;
pthread_mutex_init(&g_ping_mutex,NULL);
pthread_cond_init(&g_ping_cond,NULL);
pthread_create(&id,NULL,s_ping_thread,(void *)newconn);
a_conn(&sock->conn,newconn);
#ifndef NDEBUG
_("Accepting connection...\n");
#endif
if (sock->has_callback){
sock->func(newconn);
#ifndef NDEBUG
_("Accepted connection\n");
#endif
}
}
}
return 0;
}
void
start_accept(sock,join)
Socket* sock;
bool join;
{
pthread_t id;
pthread_attr_t attr;
if (!sock)
return;
if (!sock->conn){
sock->conn = (Connection *)MyMalloc(sizeof(*sock->conn));
if (!sock->conn)
return;
}
set_nonblocking(sock->fd);
set_nonblocking(sock->conn->fd);
pthread_attr_init(&attr);
pthread_mutex_init(&g_socket_mutex,NULL);
if (join){
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
}else{
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
}
pthread_create(&id,&attr,s_accept_connections,sock);
if (join){
pthread_join(id,NULL);
pthread_attr_destroy(&attr);
pthread_mutex_destroy(&g_socket_mutex);
}
}
It simply gives 100% cpu, any ideas? if more code needed, ill post
What makes you believe that pthread_mutex_lock() is responsible for the CPU usage ?
Use a debugger to find out what is happening.
My guess is there is something wrong with your socket, making your accept() call non-blocking.
Check the return value/message (with perror() if you are running linux).
EDIT :
You need to know which piece of code is looping a debugger can help you to find this.
You have a while(true) loop that is very likely to be responsible for the enless loop and the 100% CPU usage. It should be ok since you have a call to accept() (here :newfd = accept(sock->fd,(SOCKADDR *)&newsockaddr,&tmp);) that is supposed to stop the thread/process until the next client connection. But if your socket is not correctly initialized accept() may return an error without waiting.
Related
I am trying to group the operation under libmodbus for Mod-bus connection and get-value into two simpler function as below.
However, it always cause Segmentation fault (core dumped) when I try to get value from the device.(get_float, modbus_read_registers)
Can anyone tell me how to fix it?
int connect(char *ip_addr, struct timeval timeout, modbus_t *ctx){
int fail = 0;
ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
modbus_set_slave(ctx, MODBUS_DEVICE_ID);
modbus_set_debug(ctx, MODBUS_DEBUG);
timeout.tv_sec = MODBUS_TIMEOUT_SEC;
timeout.tv_usec = MODBUS_TIMEOUT_USEC;
modbus_get_byte_timeout(ctx, &timeout.tv_sec, &timeout.tv_usec);
timeout.tv_sec = MODBUS_TIMEOUT_SEC;
timeout.tv_usec = MODBUS_TIMEOUT_USEC;
modbus_set_response_timeout(ctx, timeout.tv_sec, timeout.tv_usec);
fail = modbus_connect(ctx);
if (fail == -1) {
fprintf(stderr, "Connection failed: %s\n",
modbus_strerror(errno));
modbus_free(ctx);
fail = -1;
}
return fail;
}
int get_float(modbus_t *ctx, uint16_t addr, float *val){
int fail = 0;
__uint16_t value[2];
printf("1\n");
fail = modbus_read_registers(ctx, (addr-1), 2, value);
printf("2\n");
if(fail <= 0) {
fprintf(stderr, "Reading error(%d): %s\n", addr, modbus_strerror(errno));
} else {
*val = modbus_get_float_abcd(value);
}
return fail;
}
Besides, I can successfully run the similar code when I put them in same function as below:
int connect_n_getFloat(char *ip_addr, uint16_t addr, float *val){
int fail = 0;
modbus_t *ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
ctxConfig(ctx);
if (modbus_connect(ctx) == 0) {
__uint16_t value[2];
if(modbus_read_registers(ctx, (addr-1), 2, value) > 0) {
*val = modbus_get_float_abcd(value);
} else {
fprintf(stderr, "Reading error(%d): %s\n", addr, modbus_strerror(errno));
fail = -1;
}
} else {
fprintf(stderr, "Connection failed: %s\n",
modbus_strerror(errno));
modbus_free(ctx);
fail = -1;
}
return fail;
}
You're passing a context pointer to the connect function, but should be passing a pointer to a pointer, so you can return the allocated context and continue using it in further calls.
Change the function signature, and ctx usage, from
int connect(char *ip_addr, struct timeval timeout, modbus_t *ctx) {
int fail = 0;
ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
to
int connect(char *ip_addr, struct timeval timeout, modbus_t **ctx) {
int fail = 0;
*ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
This also explains why it works when you put them in the same function.
PS: I am very new to threads.
I have a problem where i need to wait for connection requests(completely arbitrary number of times) from clients, accept a connection on a socket, create a worker thread after connection. The created thread then creates a char array, works on it and needs to pass it to the parent process.
I have been able to create the threads in a while loop like
while ((new_socket = accept(srv_sock, (struct sockaddr *)&client, &c)) != INVALID_SOCKET)
{
puts("\nConnection accepted");
_beginthreadex(0, 0, handle_client, &new_socket, 0, 0);
}
I have seen that pthread_join() can be used to pass data from thread to parent process(in unix). My question is, how can I integrate it into a loop in the main process.
I expect the following approach will result in a situation where no more than one connection can be established between client and server at a time,which is not desired.
while ((new_socket = accept(srv_sock, (struct sockaddr *)&client, &c)) != INVALID_SOCKET)
{
puts("\nConnection accepted");
_beginthreadex(0, 0, handle_client, &new_socket, 0, 0);
pthread_join(thread_id,&my_array);
}
EDIT: I would be happy to know if what I want is impossible or if there are alternatives to pthread_join(). or its windows equivalent.
EDIT: I know that pthread_join() is for Unix and have read that WaitForMultipleObjects() is its equivalent for windows. In any case I still haven't been able to figure out a solution.
I have seen that pthread_join() can be used to pass data from thread to parent process.
That is not entirely correct. You can pass a pointer when you exit a thread, and collect that pointer using pthread_join. You have to implement all the logic yourself. The API does not know (or care) what the pointer is. Threads don't have parents and children, they are siblings.
Example for a creator and a reaper:
global
struct VarLengthArray {
size_t count;
MyElem data[1];
};
exiting thread:
// allocate the result
size_t count = ...;
VarLengthArray *retval = malloc(
sizeof(VarLengthArray) +
sizeof(MyElem) * (count > 0 ? count - 1 : 0)
);
// fill the result
retval->count = count;
for (size_t i = 0; i < retval->count; ++i) {
retval->data[i] = ...;
}
pthread_exit(retval);
collecting thread:
// collect the result
void *retval_;
if (pthread_join(thread_one_id, &retval_) != 0) {
// handle error
}
VarLengthArray *retval = retval_;
// use the result
for (size_t i = 0; i < retval->count; ++i) {
printf("retval->[%u] = %s\n", (unsigned) i, retval->data[i].string_value);
}
// deallocate the result
free(retval);
A full example using a condition variable and multiple creators:
#include <limits.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct Datum {
struct Datum *next;
char some_data[32];
} Datum;
typedef struct SharedData {
pthread_mutex_t mutex;
pthread_cond_t cond_empty;
unsigned seed;
Datum *head, *tail;
unsigned children_alive;
} SharedData;
static void *thread_logic(void *argv_);
int main(int argc, char **argv) {
unsigned thread_count = 2;
if (argc > 1) {
if (sscanf(argv[1], " %u ", &thread_count) != 1) {
fprintf(stderr, "Usage: %s [thread_count]\n", argv[0]);
return 1;
}
}
// initialize shared data
SharedData shared_data;
pthread_mutex_init(&shared_data.mutex, NULL);
pthread_cond_init(&shared_data.cond_empty, NULL);
shared_data.seed = time(NULL);
shared_data.head = NULL;
shared_data.tail = NULL;
shared_data.children_alive = 0;
// start threads detached, so you don't have to call pthread_join
pthread_t *child_ids = malloc(sizeof(pthread_t) * thread_count);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// start the threads
pthread_mutex_lock(&shared_data.mutex);
for (unsigned i = 0; i < thread_count; ++i) {
if (pthread_create(&child_ids[i], &attr, thread_logic, &shared_data) != 0) {
perror("pthread_create");
} else {
++shared_data.children_alive;
}
}
pthread_mutex_unlock(&shared_data.mutex);
pthread_attr_destroy(&attr);
// loop until all threads are dead
while (shared_data.children_alive > 0) {
// a condition variable: wait until there is data you can read
pthread_mutex_lock(&shared_data.mutex);
while (shared_data.head == NULL) {
pthread_cond_wait(&shared_data.cond_empty, &shared_data.mutex);
}
// collect a first datum
Datum *datum = shared_data.head;
if (datum->next != NULL) {
shared_data.head = datum->next;
} else {
shared_data.head = shared_data.tail = NULL;
}
pthread_mutex_unlock(&shared_data.mutex);
// handle the data (outside of the mutex lock)
printf("Got data: %s\n", datum->some_data);
free(datum);
}
return 0;
}
static void *thread_logic(void *shared_data_) {
SharedData *shared_data = shared_data_;
while (1) {
pthread_mutex_lock(&shared_data->mutex);
// create some data
useconds_t timeout = (
(((float) (unsigned) rand_r(&shared_data->seed)) / UINT_MAX) *
1000000
);
Datum *datum = malloc(sizeof(Datum));
datum->next = NULL;
if (timeout < 1000000 / 25) {
--shared_data->children_alive;
snprintf(datum->some_data, sizeof(datum->some_data), "I'm done\n");
} else {
snprintf(
datum->some_data, sizeof(datum->some_data),
"Sleeping for %uus\n", timeout
);
}
// append the datum
if (shared_data->head) {
shared_data->tail->next = datum;
} else {
shared_data->head = datum;
pthread_cond_signal(&shared_data->cond_empty);
}
shared_data->tail = datum;
pthread_mutex_unlock(&shared_data->mutex);
// most likely it takes some time to create the data
// do lengthly tasks outside of the mutex lock
if (timeout < 1000000 / 25) {
return NULL;
} else {
usleep(timeout);
}
}
}
[EDIT]I added all my main code and some of the external functions used by this code. The code is quite long, but in summary it sends a message to a device measuring some parameters of the water in a container, and the device responds with the corresponding value measured by the sensor.
After that the code uses this value to modify the level and temperature of water. Prints the current status of the container and makes a log.txt file.[/Edit]
I want to do a constructor object-oriented-like function in C, but the address of my structure and its members are not being changed after I malloc() them. I saw this answer Changing address contained by pointer using function and I got an idea of what my problem is, but still can't solve it.
Below is my code that is doing the constructor:
udp.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "udp.h"
#define BUF_SIZE 1000
#define HEADER_SIZE
typedef struct{
int socket;
char header[4];
float *send_value;
char *message_buffer;
}message;
void build_message(message **msg, int socket, char header[], float *send_value){
*msg = (message *)malloc(sizeof(message));
(*msg)->socket = socket;
strncpy((*msg)->header, header, 4);
(*msg)->send_value = send_value;
(*msg)->message_buffer = NULL;
(*msg)->message_buffer = malloc(BUF_SIZE);
//(**msg).message_buffer = (char *)(msg+sizeof(int) + sizeof(float *) + sizeof(char *)*3);
}
int prepara_socket_cliente(char *host, char *porta)
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int sfd, s;
/* Obtain address(es) matching host/port */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4/ or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = 0;
hints.ai_protocol = 0; /* Any protocol */
s = getaddrinfo(host, porta, &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully connect(2).
If socket(2) (or connect(2)) fails, we (close the socket
and) try the next address. */
for( rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1)
continue;
if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
break; /* Success */
close(sfd);
}
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not connect\n");
exit(EXIT_FAILURE);
}
freeaddrinfo(result); /* No longer needed */
return sfd;
}
float receive_message(message *msg){
ssize_t nread;
int len;
//sprintf(msg->message_buffer, "%s0.0", msg->header);
len = strlen(msg->message_buffer)+1;
int rc;
if (len + 1 > BUF_SIZE){
fprintf(stderr, "Ignoring long message in argument\n");
exit(EXIT_FAILURE);
}
if((rc = write(msg->socket, msg->message_buffer, len)) != len){
printf("%d, %d\n", len, rc);
fprintf(stderr, "partial/failed write\n");
exit(EXIT_FAILURE);
}
nread = read(msg->socket, msg->message_buffer, BUF_SIZE);
if (nread == -1){
perror("read");
exit(EXIT_FAILURE);
}
return atof(msg->message_buffer+3);
}
int send_message(message *msg){
ssize_t nread;
int len;
//sprintf(msg->message_buffer, "%s%.1f", msg->header, *msg->send_value);
len = strlen(msg->message_buffer)+1;
int rc;
if (len + 1 > BUF_SIZE){
fprintf(stderr, "Ignoring long message in argument\n");
exit(EXIT_FAILURE);
}
if((rc = write(msg->socket, msg->message_buffer, len)) != len){
printf("%d, %d\n", len, rc);
fprintf(stderr, "partial/failed write\n");
exit(EXIT_FAILURE);
}
nread = read(msg->socket, msg->message_buffer, BUF_SIZE);
if (nread == -1){
perror("read");
exit(EXIT_FAILURE);
}
return 0;
}
main.c
#include<pthread.h>
#include<stdio.h>
#include<errno.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<unistd.h>
#include<math.h>
#include<time.h>
#include<termios.h>
#include"controller.h"
#include"screen.h"
#include"myIO.h"
#include"my_time.h"
#include"data_structures.h"
#include"udp.h"
#define NUM_THREADS 5
#define MAX_PARAM_SIZE 20
#define MAX_BUFFER_SIZE 1200
//variables
typedef enum {IDLE, QUIT, CHANGE_LEVEL_REF, CHANGE_TEMP_REF} command_type;
struct timespec t1;
struct timespec t2;
pthread_cond_t screen = PTHREAD_COND_INITIALIZER;
pthread_cond_t cmd = PTHREAD_COND_INITIALIZER;
pthread_cond_t barrier = PTHREAD_COND_INITIALIZER;
int count[2] = {0,0};
command_type command = IDLE;
double_buffer* log_buffer;
char* port = NULL;
char* host = NULL;;
int socket_cliente;
real Ta, Ti, No;
real T=0;
real H=0;
real Q=0;
real Nf=0;
real Ni=0;
real Na=0;
real href = 2.0;
real tref = 25.0;
pthread_mutex_t em_scan;
pthread_mutex_t em;
void init(){
port = (char *)malloc(sizeof(char)*MAX_PARAM_SIZE);
host = (char *)malloc(sizeof(char)*MAX_PARAM_SIZE);
log_buffer = build_double_buffer();
}
//threads
void *LevelControl(void *threadid){
/**********************************************************
*thread responsible for controling the water level
*********************************************************/
controller* levelControl = NULL;
levelControl = build_controller();
levelControl->kp = 10000.0;
levelControl->ki = 0.0;
levelControl->kd = 0.0;
levelControl->error_thresh = 1.0;
levelControl->step_time = 0.7;
levelControl->max_actuator_value = 100.0;
levelControl->min_actuator_value = 0.0;
int intervalo = 90000000;
message *message_H = NULL;
build_message(&message_H, socket_cliente, "sh-", &H);
sprintf(message_H->message_buffer, "%s0.0", message_H->header);
message *message_Nf = NULL;
build_message(&message_Nf, socket_cliente, "anf", &Nf);
message *message_Ni = NULL;
build_message(&message_Ni, socket_cliente, "ani", &Ni);
loop_1:
if(command != QUIT){
pthread_mutex_lock(&em);
H = receive_message(message_H);
levelControl->error = href - H;
if(levelControl->error < 0.0){
levelControl->error = -levelControl->error;
Nf = PID_Update(levelControl);
Ni = 0.0;
}else{
Ni = PID_Update(levelControl);
Nf = 0.0;
}
sprintf(message_Nf->message_buffer, "%s%f", message_Nf->header, *message_Nf->send_value);
send_message(message_Nf);
sprintf(message_Ni->message_buffer, "%s%f", message_Ni->header, *message_Ni->send_value);
send_message(message_Ni);
count[1] = 1;
if((count[0] == 1) & (count[1] == 1)) pthread_cond_signal(&barrier);
next_timer(t1, intervalo);
pthread_mutex_unlock(&em);
goto loop_1;
}else return NULL;
}
void *TempControl(void *threadid){
/**********************************************************
* thread responsible for controling the temperature
*********************************************************/
controller *tempControl = NULL;
tempControl = build_controller();
tempControl->kp = 10000.0;
tempControl->ki = 0.0;
tempControl->kd = 0.0;
tempControl->error_thresh = 20.0;
tempControl->step_time = 0.7;
tempControl->max_actuator_value = 10000.0;
tempControl->min_actuator_value = 0.0;
int intervalo = 70000000;
message *message_T = NULL;
build_message(&message_T, socket_cliente, "st-", &T);
sprintf(message_T->message_buffer, "%s0.0", message_T->header);
message *message_Q = NULL;
build_message(&message_Q, socket_cliente, "aq-", &Q);
message *message_Na = NULL;
build_message(&message_Na, socket_cliente, "ana", &Na);
char *log_string = NULL;
log_string = (char *)malloc(sizeof(char)*MAX_BUFFER_SIZE);
// while(command != QUIT){
loop_2:
if(command != QUIT){
pthread_mutex_lock(&em);
T = receive_message(message_T);
tempControl->error = tref - T;
Q = PID_Update(tempControl);
sprintf(message_Q->message_buffer, "%s%f", message_Q->header, *message_Q->send_value);
send_message(message_Q);
if(Q == tempControl->max_actuator_value){
Na = 10.0;
}else if(Q == tempControl->min_actuator_value){
Na = 0.0;
}
sprintf(message_Na->message_buffer, "%s%f", message_Na->header, *message_Na->send_value);
send_message(message_Na);
count[0] = 1;
if((count[0] == 1) & (count[1] == 1)) pthread_cond_signal(&barrier);
pthread_mutex_unlock(&em);
sprintf(log_string, "Temperura: %f\n", T);
setDoubleBuffer(log_buffer, log_string);
next_timer(t2, intervalo);
goto loop_2;
}else return NULL;
// pthread_exit(NULL);
}
void *Status(void *threadid){
/**********************************************************
*thread responsible for printing the current status on
*the screen and setting tref and href
*********************************************************/
message *message_Ta = NULL;
build_message(&message_Ta, socket_cliente, "sta", &Ta);
sprintf(message_Ta->message_buffer, "%s0.0", message_Ta->header);
message *message_Ti = NULL;
build_message(&message_Ti, socket_cliente, "sti", &Ti);
sprintf(message_Ti->message_buffer, "%s0.0", message_Ti->header);
message *message_No = NULL;
build_message(&message_No, socket_cliente, "sno", &No);
sprintf(message_No->message_buffer, "%s0.0", message_No->header);
pthread_mutex_lock(&em);
while((count[0] != 1) | (count[1] != 1)) pthread_cond_wait(&barrier, &em);
pthread_mutex_unlock(&em);
//while(command != QUIT){
loop_3:
switch(command){
case IDLE:
pthread_mutex_lock(&em);
clearScreen();
Ta = receive_message(message_Ta);
Ti = receive_message(message_Ti);
No = receive_message(message_No);
printf("/********************************************************************************************************\n");
printf("*STATUS\n");
printf("*reference temperature: %f\n", tref);
printf("*reference water level: %f\n", href);
printf("*current temperature: %f\n", T);
printf("*current water level: %f\n", H);
printf("*other sensor value => Ni = %f, No = %f, Na = %f, Nf = %f, Ta = %f, Ti = %f\n", Ni, No, Na, Nf, Ta,Ti);
printf("*\n");
printf("*\n");
printf("*\n");
printf("*(q)uit, change (l)evel reference, change (t)emperature reference\n");
pthread_mutex_unlock(&em);
sleep(1);
break;
case CHANGE_LEVEL_REF:
pthread_mutex_lock(&em_scan);
printf("insert new Level reference\n");
scanf("%f", &href);
pthread_cond_signal(&screen);
while(command != IDLE){
pthread_cond_wait(&cmd, &em_scan);
}
pthread_mutex_unlock(&em_scan);
break;
case CHANGE_TEMP_REF:
pthread_mutex_lock(&em_scan);
printf("insert new Temperature reference\n");
scanf("%f", &tref);
pthread_cond_signal(&screen);
while(command != IDLE){
pthread_cond_wait(&cmd, &em_scan);
}
pthread_mutex_unlock(&em_scan);
case QUIT:
fprintf(stderr, "get saiu\n");
return NULL;
}
goto loop_3;
//return NULL;
}
void *GetReferences(void *threadid){
/**********************************************************
*thread responsible for changing the program mode
*********************************************************/
char temp;
//while(command != QUIT){
loop_4:
temp = getch();
switch(temp){
case 'q':
command = QUIT;
printf("%c\n --------------------------------------------------------\n", temp);
return NULL;
case 'l':
pthread_mutex_lock(&em_scan);
command = CHANGE_LEVEL_REF;
pthread_cond_wait(&screen, &em_scan);
command = IDLE;
pthread_cond_signal(&cmd);
pthread_mutex_unlock(&em_scan);
break;
case 't':
pthread_mutex_lock(&em_scan);
command = CHANGE_TEMP_REF;
pthread_cond_wait(&screen, &em_scan);
command = IDLE;
pthread_cond_signal(&cmd);
pthread_mutex_unlock(&em_scan);
}
goto loop_4;
}
void *Log(void *threadid){
char *receive_buffer = NULL;
receive_buffer = (char *)malloc(sizeof(char)*MAX_BUFFER_SIZE);
//while(command != QUIT){
loop_5:
if(command != QUIT){
get_buffer(receive_buffer, log_buffer);
write_log(receive_buffer);
goto loop_5;
}else return NULL;
}
int main (int argc, char *argv[]){
init();
pthread_mutex_init(&em_scan, NULL);
pthread_mutex_init(&em, NULL);
init_nano_timer(t1);
init_nano_timer(t2);
clearScreen();
printf("Enter the port where to be used in the udp communication\n");
scanf("%s", port);
strcpy(host, "localhost");
socket_cliente = prepara_socket_cliente(host, port);
pthread_t threads[NUM_THREADS];
int rc;
int t;
void *threadName[NUM_THREADS];
threadName[0] = TempControl;
threadName[1] = LevelControl;
threadName[2] = Status;
threadName[3] = GetReferences;
threadName[4] = Log;
for(t=0; t<NUM_THREADS; t++){
rc = pthread_create(&threads[t], NULL, threadName[t], (void *)t);
if(rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(1);
}
}
for(t=0; t<NUM_THREADS; t++){
rc = pthread_join(threads[t], NULL);
if(rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(1);
}
}
return 0;
}
Btw, I am using threads in these code, would this code be thread-safe even without mutexes?
As #Sourav Ghosh rightly commented you:
void build_message(message **msg, int socket, char header[], float *send_value)
{
*msg = malloc(sizeof(message));
(*msg)->socket = socket;
strncpy((*msg)->header, header, 4);
(*msg)->send_value = send_value;
(*msg)->message_buffer = malloc(BUF_SIZE);
}
Change the structure to:
typedef struct{
int socket;
char header[4];
float *send_value;
char *message_buffer;
}message;
I'm trying to debug a code that is using a libevent library. In that library, there is a function event_new that is suppose to create an event_cb. Somehow after I dispatch the event base, the event_cb cannot be called or accessed. This problem only happens on hpux itanium. This code works on hpux pa-risc, Redhat, AIX, and Solaris. Is there any certain thing that need to be set?
This is part of the code
int ttypread (int fd, Header *h, char **buf)
{
int c,k;
struct user_data user_data;
struct bufferevent *in_buffer;
struct event_config *evconfig;
log_debug("inside ttypread");
in_buffer = NULL;
user_data.fd = fd;
user_data.h = h;
user_data.buf = buf;
log_debug("from user_data, fd = %d",user_data.fd); //the log_debug is a debugging function for me to check the value sent by the system. I use it to compare between each platform
log_debug("from user_data, buf = %s",user_data.buf);
log_debug("from user_data, h.len = %d",user_data.h->len);
log_debug("from user_data, h.type = %d",user_data.h->type);
evconfig = event_config_new();
if (evconfig == NULL) {
log_error("event_config_new failed");
return -1;
}
if (event_config_require_features(evconfig, EV_FEATURE_FDS)!=0) {
log_error("event_config_require_features failed");
return -1;
}
base = event_base_new_with_config(evconfig);
if (!base) {
log_error("ttypread:event_base_new failed");
return -1;
}
const char* method; //these 3 lines are the new line edited
method = event_base_get_method(base);
log_debug("ttyread is using method = %s",method);
ev = event_new(base, fd, EV_READ|EV_PERSIST, ttypread_event_cb, &user_data);
c = event_add(ev, NULL);
log_debug("ttypread passed event_add with c value is %d",c);
in_buffer = bufferevent_socket_new(base, STDIN_FILENO, BEV_OPT_CLOSE_ON_FREE);
log_debug("ttypread passed bufferevent_socket_new");
if(in_buffer == NULL){
log_debug("problem with bufferevent_socket_new");
}
bufferevent_setcb(in_buffer, in_read_cb, NULL, in_event_cb, NULL);
bufferevent_disable(in_buffer, EV_WRITE);
bufferevent_enable(in_buffer, EV_READ);
k =event_base_dispatch(base);
log_debug("event_base have been dispatched"); //when looking at the debugging file, the other plaform will go to ttypread_event_cb function. But for hpux itanium, it stays here.
if (k == 0){
log_debug("event_base_dispatch returned 0");
} else if (k == -1){
log_debug("event_base_dispatch returned -1");
} else {
log_debug("event_base_dispatch returned 1");
}
event_base_free(base);
event_free(ev);
log_debug("finish ttypread");
log_debug("ttypread_ret will return [%d]",ttypread_ret);
return ttypread_ret;
}
void ttypread_event_cb(evutil_socket_t fd, short events, void *arg)
{
int nread;
struct timeval t;
struct user_data *user_data;
user_data = (struct user_data*)arg;
nread = 0;
log_debug("inside ttypread_event_cb");
if (events & EV_READ) {
log_debug("got events & EV_READ");
nread = ttyread(fd, user_data->h, user_data->buf);
if (nread == -1) {
ttypread_ret = -1;
event_del(ev);
event_base_loopexit(base, NULL);
} else if (nread == 0) {
if (access(input_filename, F_OK)!=0) {
log_debug("cannot access [%s]",input_filename);
tcsetattr(0, TCSANOW, &old); /* Return terminal state */
exit(EXIT_SUCCESS);
}
t.tv_sec = 0;
t.tv_usec = 250000;
select(0, 0, 0, 0, &t);
} else {
ttypread_ret = 1;
event_del(ev);
event_base_loopexit(base, NULL);
}
}
else if (events & EV_WRITE) {
log_debug("got events & EV_WRITE");
}
}
Not sure if this help. But just some info on the hpux itanium
uname -a = HP-UX hpux-ita B.11.23 U ia64
If you need any additional info or other declaration on function, just leave a comment and I will edit the question.
EDIT : i've added a function inside ttypread. Somehow for hpux itanium its returning devpoll while other platform are returning poll. Im not sure if this is the problem. But if that is so, is there any way for me to change it?
After checking the result from event_base_get_method, I found out that only on my hpux-itanium used devpoll method. This is how I solve it.
char string[8] = "devpoll";
struct user_data user_data;
struct bufferevent *in_buffer;
struct event_config *evconfig;
const char *method;
const char *devpoll;
devpoll = string;
in_buffer = NULL;
user_data.fd = fd;
user_data.h = h;
user_data.buf = buf;
evconfig = event_config_new();
if (evconfig == NULL) {
log_error("event_config_new failed");
return -1;
}
if (event_config_require_features(evconfig, EV_FEATURE_FDS)!=0) {
log_error("event_config_require_features failed");
return -1;
}
if (event_config_avoid_method(evconfig,devpoll) != 0)
{
log_error("Failed to ignore devpoll method");
}
Force the libevent to ignore using devpoll and use poll instead.
I have a some multithreading application. This is a part of main function:
/* ...some code before... */
for(i=0; i<THREADS_COUNT; i++){
status = pthread_create(&threads[i], NULL, thread_main, NULL);
if(status < 0){
fprintf(stderr, "threads error\n");
exit(2);
}
}
status = sem_init(&sem, 0, 0);
if(status < 0){
fprintf(stderr, "sem_init error\n");
exit(4);
}
/* recv loop */
while (1) {
rv = recv(fd, buf, BUFSIZE, 0);
if(rv >= 0){
current = malloc(sizeof(struct queue_msg_list));
/* adding to our local queue */
if(current != NULL){
current->rv = rv;
current->h = h;
memcpy(&(current->buf), &buf, BUFSIZE);
current->next = NULL;
if(main_head == NULL){
main_head = main_tail = current;
}
else {
main_tail->next = current;
main_tail = current;
}
count++;
}
/* if we can carry the local queue to the queue for threads then we are doing it */
if(!pthread_mutex_trylock(&mlock)){
if(thread_head == NULL){
/* if the threads-queue is empty then replace queues */
thread_head = main_head;
thread_tail = main_tail;
} else {
/* if the threads-queue is not empty then add the local queue to the threads-queue */
thread_tail->next = main_head;
thread_tail = main_tail;
}
/* we increasing a semaphore of number of added elements */
for(i=0; i<count; i++){
sem_post(&sem);
printf("sem_post \n");
}
count = 0;
pthread_mutex_unlock(&mlock);
main_head = NULL;
main_tail = NULL;
}
}
}
/* ...some code after... */
And this is a function for threads:
void *thread_main(void *arg)
{
struct queue_msg_list *current;
char buf[BUFSIZE] __attribute__ ((aligned));
struct nfq_handle *h;
int rv;
while(1){
sem_wait(&sem);
pthread_mutex_lock(&mlock);
/* if no blocking then we are working with packet and removing it from list after */
current = thread_head;
rv = current->rv;
h = current->h;
memcpy(&buf, &(current->buf), BUFSIZE);
thread_head = thread_head->next;
pthread_mutex_unlock(&mlock);
nfq_handle_packet(h, buf, rv);
free(current);
}
}
This application always works true on PC. I have put this application to some router (linux kernel version in firmware is 2.6.30). It works correctly sometimes but sometimes it works incorrectly. :)
Threads hang on calling sem_wait(&sem); sometimes but the semaphore value is above zero (1, 2, 3, etc). Why?
P.S. I tried to check the return value of sem_wait(&sem); but did not get it.