Related
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.
I am currently working on a project involving a Cyclone V ARM Cortex A9 Processor and an external device. I am relatively new in C Programming. I am using the UART interface of the processor to send and receive data from the external with help of APIs in C. When i compile my code, I get warnings that I am passing arguments that make pointer from integer without a cast in the function alt_16550_fifo_write(). Can someone please help?
Below is my code
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h> // string function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
#include <stdbool.h>
#include <sys/types.h>
#include "ergo.h"
#include "alt_clock_manager.h"
#include "hwlib.h"
#include "alt_clock_group.h"
#include "alt_hwlibs_ver.h"
#include "alt_16550_uart.h"
#include "uart.h"
#include "socal/alt_clkmgr.h"
#include "socal/alt_rstmgr.h"
#include "socal/alt_uart.h"
#include "socal/hps.h"
#include "socal/socal.h"
/* commands to control the ergo bike */
#define ERGO_CMD_GET_ADDRESS 0x11
#define ERGO_CMD_RUN_DATA 0x40
#define ERGO_CMD_SET_WATT 0x51
#define UART_MAX_DATA 20
#define enable_init TRUE
/*Global Variables*/
ergo_run_data_t ergo_run_data;
u_int8_t ergo_adr_int;
/* External Functions that are called in the main function*/
static ALT_STATUS_CODE alt_16550_reset_helper(ALT_16550_HANDLE_t * handle, bool enable_init);
static inline uint32_t alt_read_word_helper(const void * addr);
static ALT_STATUS_CODE alt_16550_write_divisor_helper(ALT_16550_HANDLE_t * handle,uint32_t divisor);
ALT_STATUS_CODE alt_clk_clock_enable(ALT_CLK_t ALT_CLK_L4_SP);
ALT_STATUS_CODE alt_clk_is_enabled(ALT_CLK_t ALT_CLK_L4_SP);
ALT_STATUS_CODE alt_clk_freq_get(ALT_CLK_t ALT_CLK_L4_SP,alt_freq_t* freq);
ALT_STATUS_CODE alt_16550_fifo_write(ALT_16550_HANDLE_t * handle,const char * buffer,size_t count);
void ergo_get_address(ALT_16550_HANDLE_t * handle);
void ergo_get_run_data(void);
void ergo_set_watt(u_int8_t ergo_adr_int, u_int8_t watt);
void ergo_reset(ALT_16550_HANDLE_t * handle,u_int8_t ergo_adr_int);
void ergo_break(void);
/*function to enable the SOCFPGA UART Clock*/
ALT_STATUS_CODE alt_clk_clock_enable(ALT_CLK_t ALT_CLK_L4_SP)
{
if (alt_clk_clock_enable(ALT_CLK_L4_SP) != ALT_E_ERROR)
{
return ALT_E_SUCCESS; // The operation was successfull
}
else
{
return ALT_E_ERROR; // The operation was not successfull
}
}
/*Function to check whether the SOCFPGA Clock is enabled*/
ALT_STATUS_CODE alt_clk_is_enabled(ALT_CLK_t ALT_CLK_L4_SP)
{
ALT_16550_HANDLE_t * handle;
handle->clock_freq = 0;
if (alt_clk_is_enabled(ALT_CLK_L4_SP) != ALT_E_TRUE)
{
return ALT_E_BAD_CLK;
}
else
{
ALT_STATUS_CODE status;
status = alt_clk_freq_get(ALT_CLK_L4_SP, &handle->clock_freq);
}
}
//function to get the clock frequency
ALT_STATUS_CODE alt_clk_freq_get(ALT_CLK_t ALT_CLK_L4_SP,alt_freq_t* freq)
{
ALT_16550_HANDLE_t * handle;
handle->clock_freq = 0;
ALT_STATUS_CODE status;
status = alt_clk_freq_get(ALT_CLK_L4_SP, &handle->clock_freq);
if (status != ALT_E_SUCCESS)
{
return status;
}
}
struct uart_data_t
{
size_t tx_count; /*amount of data to send*/
char tx_buffer[UART_MAX_DATA]; /*data to send*/
size_t rx_count; /*amount of data to send*/
char rx_buffer[UART_MAX_DATA]; /*data received*/
}uart_data_t;
/*==========================UART functions======================*/
/*----------------------------- uart_init() -------------------------*/
/**
* Übergabeparameter: -
* Return: -
* Funktion: Initialisiert UART-Schnittstelle
*---------------------------------------------------------------------*/
int main()
{
/* Open File Descriptor */
int USB = open( "/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NONBLOCK);
//Error Handling
if ( USB < 0 )
{
printf("Error beim oeffnen");
}
// Configure Port
struct termios tty;
struct termios tty_old;
memset (&tty, 0, sizeof tty);
// Error Handling
if ( tcgetattr ( USB, &tty ) != 0 )
{
printf("error beim tcgetattr");
}
// Save old tty parameters
tty_old = tty;
ALT_16550_HANDLE_t * handle;
handle->data;
handle->fcr;
handle->clock_freq;
handle->location; //ALT_UART0_ADDR
handle->device;
//ALT_16550_DEVICE_SOCFPGA_UART0 = 0; //This option selects UART0 in the SoC FPGA
ALT_16550_DEVICE_t device;
ALT_STATUS_CODE status;
alt_freq_t clock_freq;
void *location;
const void * addr;
bool enable_init;
uint32_t baudrate = ALT_16550_BAUDRATE_9600;
uint32_t divisor; //((handle->clock_freq + (8 * baudrate)) / (16 * baudrate));
printf("Program start \n");
// Enable the UART Clock
alt_clk_clock_enable(ALT_CLK_L4_SP);
// Helper function to reset and Initialise the UART (UART 0)
alt_16550_reset_helper(handle, enable_init);
// Helper function to carryout the actual register read.
alt_read_word_helper(addr);
//Helper function to write the divisor in Hardware
alt_16550_write_divisor_helper(handle,divisor);
//Enable the UART (UART 0)
alt_16550_enable(handle);
//Enable the FIFO
alt_16550_fifo_enable(handle);
//Get the Ergometer address
ergo_get_address(handle);
return 0;
}
/*--------------------------- ergo_get_adr() ------------------------*/
/**
* Übergabeparameter: -
* Return: -
* Funktion: Holen der Ergometer-Adreesse (1 Byte)
*---------------------------------------------------------------------*/
void ergo_get_address(ALT_16550_HANDLE_t * handle)
{
struct uart_data_t data;
/* build up data frame for address request */
data.tx_count = 1; // amount of data to send
data.tx_buffer[0] = ERGO_CMD_GET_ADDRESS;
data.rx_count = 2; /*amount of data to receive*/
/* get address from ergo bike */
alt_16550_fifo_write(handle, *ERGO_CMD_GET_ADDRESS,1);
alt_16550_fifo_read(handle,data.rx_buffer,2);
/* save ergo address if the bike responded */
if(data.rx_buffer[0] == ERGO_CMD_GET_ADDRESS)
{
ergo_adr_int = data.rx_buffer[1];
printf("%d\n",data.rx_buffer[1]);
}
/* wait for 50ms */
ergo_break();
return;
}
/*---------------------------- ergo_reset() -------------------------*/
/**
* Übergabeparameter: u_int8_t ergo_adr_int
* Return: -
* Funktion: Setzt Ergometer zurück
*---------------------------------------------------------------------*/
void ergo_reset(ALT_16550_HANDLE_t * handle,u_int8_t ergo_adr_int)
{
alt_16550_fifo_write(handle,0x12,1);
alt_16550_fifo_write(handle,ergo_adr_int,1);
ergo_break();
return;
}
/*---------------------------- ergo_break() -------------------------*/
/**
* Übergabeparameter: -
* Return: -
* Funktion: Wait for about 50 ms
*---------------------------------------------------------------------*/
void ergo_break(void)
{
u_int16_t d1;
u_int8_t d2;
//wait for ~50 ms
for(d1=0; d1 < 65535; d1++)
{
for(d2=0; d2 < 64; d2++)
{
}
}
return;
}
In your code, your function prototype is
ALT_STATUS_CODE alt_16550_fifo_write
(ALT_16550_HANDLE_t * handle,const char * buffer,size_t count);
the second parameter being const char * buffer.
While calling this function, you're using
void ergo_reset(ALT_16550_HANDLE_t * handle,u_int8_t ergo_adr_int)
{
alt_16550_fifo_write(handle,0x12,1);
alt_16550_fifo_write(handle,ergo_adr_int,1);
ergo_break();
return;
}
here, 0x12 and ergo_adr_int are not of type const char *.
0x12 is an integer constant (hexadecimal constant, to be precise) #.
ergo_adr_int is of u_int8_t type.
Hence the mismatch and the warning(s).
To Resolve
You need to pass a const char * variable as the second argument of the fuunction.
# :: As per C11 standard document, chapter 6.4.4.1, Integer constants,
hexadecimal-constant:
hexadecimal-prefix hexadecimal-digit
hexadecimal-constant hexadecimal-digit
Where
hexadecimal-prefix: one of
0x 0X
and
hexadecimal-digit: one of
0 1 2 3 4 5 6 7 8 9
a b c d e f
A B C D E F
Here is the declaration of you alt_16550_fifo_write function
ALT_STATUS_CODE alt_16550_fifo_write(ALT_16550_HANDLE_t * handle,const char * buffer,size_t count);
The second parameter is of a pointer type but in your program you are always passing integer values:
alt_16550_fifo_write(handle,0x12,1);
alt_16550_fifo_write(handle,ergo_adr_int,1);
You need to pass a pointer to a char. For example:
alt_16550_fifo_write(handle, &(char) {0x12}, 1);
or
char x = 0x12;
alt_16550_fifo_write(handle, &x, 1);
Prototype for alt_16550_fifo_write() is:
ALT_STATUS_CODE alt_16550_fifo_write(ALT_16550_HANDLE_t * handle,
const char * buffer, size_t count);
You are using it at two places:
alt_16550_fifo_write(handle, *ERGO_CMD_GET_ADDRESS,1);
...
alt_16550_fifo_write(handle,0x12,1);
The second parameter is wrong. It should be const char * buffer, for example some string.
I am implementing a timer using timerfd. This is a relative timer that I just need to repeat forever at the rate it is set to. I want to poll on this event and originally tried using poll. When I did this, I would see the timer event the first time and then never again. However, when I changed to using epoll (no change at all to how the timerfd was set up) it works as expected.
Here is the code with poll:
#include <sys/timerfd.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
int main(int ac, char *av[])
{
struct pollfd p;
int timerfd;
struct itimerspec timerValue;
/* clear pollfd */
bzero(&p, sizeof(p));
/* set timerfd */
timerfd = timerfd_create(CLOCK_REALTIME, 0);
if (timerfd < 0) {
printf("failed to create timer fd\n");
exit(1);
}
bzero(&timerValue, sizeof(timerValue));
timerValue.it_value.tv_sec = 1;
timerValue.it_value.tv_nsec = 0;
timerValue.it_interval.tv_sec = 1;
timerValue.it_interval.tv_nsec = 0;
/* set events */
p.fd = timerfd;
p.revents = 0;
p.events = POLLIN;
/* start timer */
if (timerfd_settime(timerfd, 0, &timerValue, NULL) < 0) {
printf("could not start timer\n");
exit(1);
}
/* wait for events */
while (1) {
int numEvents = poll(&p, 1, -1);
if (numEvents > 0) {
int timersElapsed = 0;
(void) read(p.fd, &timersElapsed, 8);
printf("timers elapsed: %d\n", timersElapsed);
}
}
exit(0);
}
And here is the code with epoll:
#include <sys/timerfd.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
int main(int ac, char *av[])
{
struct epoll_event epollEvent;
struct epoll_event newEvents;
int timerfd;
int epollfd;
struct itimerspec timerValue;
/* set timerfd */
timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
if (timerfd < 0) {
printf("failed to create timer fd\n");
exit(1);
}
bzero(&timerValue, sizeof(timerValue));
timerValue.it_value.tv_sec = 1;
timerValue.it_value.tv_nsec = 0;
timerValue.it_interval.tv_sec = 1;
timerValue.it_interval.tv_nsec = 0;
/* set events */
epollfd = epoll_create1(0);
epollEvent.events = EPOLLIN;
epollEvent.data.fd = timerfd;
epoll_ctl(epollfd, EPOLL_CTL_ADD, timerfd, &epollEvent);
/* start timer */
if (timerfd_settime(timerfd, 0, &timerValue, NULL) < 0) {
printf("could not start timer\n");
exit(1);
}
/* wait for events */
while (1) {
int numEvents = epoll_wait(epollfd, &newEvents, 1, 0);
if (numEvents > 0) {
int timersElapsed = 0;
(void) read(epollEvent.data.fd, &timersElapsed, 8);
printf("timers elapsed: %d\n", timersElapsed);
}
}
exit(0);
}
Any idea what I might be doing wrong with poll? Maybe it is not meant to be used this way with a timerfd? Thank you.
Ok, this is an old question, but nevertheless. The problem lies in these lines of code:
int timersElapsed = 0;
(void) read(p.fd, &timersElapsed, 8);
printf("timers elapsed: %d\n", timersElapsed);
int timersElapsed is 4 bytes. Reading 8 bytes into this results in a stack overflow, giving unpredictable behaviour.
Changing timersElapsed to a long int and fixing the printf did the trick for me.
long int timersElapsed = 0;
(void) read(p.fd, &timersElapsed, 8);
printf("timers elapsed: %ld\n", timersElapsed);
This appears to be an issue with Fedora (or my installation of Fedora). That system is running 3.16, and poll() does not work.
However, on a separate Ubuntu installation with 3.13, the poll() code above works just fine. As I will be using Ubuntu in the future anyway, I will not try to track down the issue on Fedora. Though I am curious if others are seeing this same issue on Fedora systems.
I faced the same problem.
After debugging, the root cause in poll example is that
timerValue should be declared as uint64_t.
- int timersElapsed = 0;
+ uint64_t timersElapsed = 0;
The man page of timerfd_create() describes this.
Operating on a timer file descriptor
The file descriptor returned by timerfd_create() supports the following
operations:
read(2)
If the timer has already expired one or more times since its settings
were last modified using timerfd_settime(), or since the last suc‐
cessful read(2), then the buffer given to read(2) returns an unsigned
8-byte integer (uint64_t) containing the number of expirations that
have occurred. (The returned value is in host byte order—that is,
the native byte order for integers on the host machine.)
I'm trying to have a process fork and run execve in the child process so that it will open a new terminal window and execute a custom command there.
The program I want to execute is gestore
These are the arguments I pass to execve:
char * argv_exec[5];
argv_exec[0]="/usr/bin/xfce4-terminal";
argv_exec[1]="--geometry";
argv_exec[2]="480x320";
argv_exec[3]="-x";
argv_exec[4]="./gestore"; // the program I want to execute in new window
argv_exec[5]=NULL;
char sess_m[80];
strcat(sess_m,"SESSION_MANAGER=");
strcat(sess_m,getenv("SESSION_MANAGER"));
char * envp[3];
envp[0]="DISPLAY=:0.0";
envp[1]=sess_m;
envp[2]=NULL;
and here I call execve:
if(pid_tv==0)
if(execve(argv_exec[0],argv_exec,&envp)==-1) {...}
but I keep getting Session manager variable not defined.
Anyone has a suggestion on why this does not work or how could I do it better?
Some re-writing, both to show more idiomatic use of a process's environment (see environ(7)) and to demonstrate some ways to avoid hard-wiring array sizes: always a source of fence-post errors in C.
See code comments for some of the explanations/justifications.
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char **environ; /* see environ(7) */
int
main(void)
{
char *argv_exec[] = {
"/usr/bin/xfce4-terminal",
"--geometry",
"480x320",
"-x",
"./gestore",
NULL };
/*
* Structure to drive search for a few variables present in
* current environment, and construct a new, minimal, environment
* containing just those values. Use the direct value from the
* current process's environ variable to set "value" (the string
* of the form "NAME=VALUE"). Just add more entries to nv to handle
* more variables; the code below will adjust sizes.
*
* Any value missing in the environment will be an error.
*/
struct {
char *name;
char *value;
} nv[] = {
{ "DISPLAY", NULL },
{ "SESSION_MANAGER", NULL }
};
/* size new_envp to have one more entry than nv */
char *new_envp[sizeof(nv) / sizeof(nv[0]) + 1];
char **e;
int i, error_flag;
pid_t pid;
/*
* For each variable needed...
*/
for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++) {
/* ...search in current environment */
for (e = environ; *e; e++) {
size_t slen = strlen(nv[i].name);
if (strncmp(*e, nv[i].name, slen) == 0 && (*e)[slen] == '=') {
nv[i].value = *e;
break;
}
}
}
/*
* Check that we found all values, setting up new_envp as we go.
*/
error_flag = 0;
for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++) {
if (nv[i].value == NULL) {
(void) fprintf(stderr, "%s not set in environment\n",
nv[i].name);
error_flag = 1;
} else {
new_envp[i] = nv[i].value;
}
}
if (error_flag) {
return 1;
}
new_envp[i] = NULL;
/* very minimal fork/exec processing */
pid = fork();
if (pid == -1) {
perror("fork");
return 1;
}
if (pid == 0) {
(void) execve(argv_exec[0], argv_exec, new_envp);
/*
* If execve succeeded, the invoked program has
* replaced this process, and will either run or
* (presumably) report its own errors. If we're
* still in control, the execve failed, so print
* an error and exit.
*/
perror(argv_exec[0]);
return 1;
} else {
if (wait(0) != pid) {
perror("wait");
return 1;
}
}
return 0;
}
I'm fairly unexperienced with C and am running into a "Bus error" that I cannot understand the cause of. I had never heard of gdb but came across it on this forum and tried using it on my problem program and got the following output:
% gdb Proc1 GNU gdb 5.0
...
This GDB was
configured as
"sparc-sun-solaris2.8"...
(no
debugging symbols found)...
(gdb) run
Starting program:
/home/0/vlcek/CSE660/Lab3/Proc1
(no
debugging symbols found)...
(no
debugging symbols found)...
(no
debugging symbols found)...
Program
received signal SIGSEGV, Segmentation
fault. 0x10a64 in main ()
I have no idea what this means, is that saying there's an error in line 10 in my code? If so, line 10 in my code is merely "int main()" so I'm not sure the issue there... When I try running the program all it says is "Bus error" so I'm not sure where to go from here. I even tried putting a printf right after main and it doesn't print the string, only gives me a Bus error.
Below is my code:
// Compilation Command: gcc -o Proc1 Proc1.c ssem.o sshm.o
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ssem.h"
#include "sshm.h"
// Code of Proc1
int main()
{int i, internal_reg;
int key1 = 111111, key2 = 222222, key3 = 333333, key4 = 444444;
/* here create and initialize all semaphores */
int sem1 = sem_create(key1, 1);
if (sem1 < 0) {
perror("sem failed");
}
int sem2 = sem_create(key2, 1);
if (sem2 < 0) {
perror("sem failed");
}
int sem3 = sem_create(key3, 1);
if (sem3 < 0) {
perror("sem failed");
}
int sem4 = sem_create(key4, 1);
if (sem4 < 0) {
perror("sem failed");
}
/* here created: shared memory array Account of size 3 */
int *Account;
int shmid = shm_get(123456, (void**) &Account, 3*sizeof(int));
if (shmid < 0) {
perror("shm failed");
}
Account[0]=10000;
Account[1]=10000;
Account[2]=10000;
/* synchronize with Proc2, Proc3 and Proc4 (4 process 4 way synchronization)*/
for (i = 0; i < 1000; i++)
{
sem_signal(sem1);
sem_signal(sem1);
sem_signal(sem1);
internal_reg = Account[0];
internal_reg = internal_reg - 200;
Account[0] = internal_reg;
/* same thing, except we're adding $100 to Account1 now... */
internal_reg = Account[1];
internal_reg = internal_reg + 200;
Account[1] = internal_reg;
if (i % 100 == 0 && i != 0) {
printf("Account 0: $%i\n", Account[0]);
printf("Account 1: $%i\n", Account[1]);
}
if (i == 300 || i == 600) {
sleep(1);
}
sem_wait(sem2);
sem_wait(sem3);
sem_wait(sem4);
}
/* Here add a code that prints contents of each account
and their sum after 100th, 200th, 300th, ...., and 1000th iterations*/
}
/*in the code above include some wait and signal operations on semaphores. Do no
t over-synchronize. */
Here is the documentation for ssem and sshm:
/*
* ssem.c
*
* Version 1.0.0
* Date : 10 Jan 2002
*
*/
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include "ssem.h"
#define PERMS 0600
static struct sembuf op_lock[1] = {
0, -1, 0
};
static struct sembuf op_unlock[1] = {
0, 1, IPC_NOWAIT
};
int sem_create(int key,int initval)
{
int semid,i;
semid = semget((key_t)key, 1, IPC_CREAT | PERMS);
for(i=0;i<initval;i++)
semop(semid,&op_unlock[0],1);
return semid;
}
int sem_open(int key)
{
int semid;
semid = semget(key,0,0);
return semid;
}
int sem_wait(int semid)
{
return semop(semid,&op_lock[0],1);
}
int sem_signal(int semid)
{
return semop(semid,&op_unlock[0],1);
}
int sem_rm(int semid)
{
return semctl(semid, 0, IPC_RMID, 0);
}
/*
* sshm.c
*
* Routines for Simpler shared memory operations
* Version : 1.0.0.
* Date : 10 Jan 2002
*
*/
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include "sshm.h"
#define PERMS 0600
int shm_get(int key, void **start_ptr, int size)
{
int shmid;
shmid = shmget((key_t) key, size, PERMS | IPC_CREAT);
(*start_ptr) = (void *) shmat(shmid, (char *) 0, 0);
return shmid;
}
int shm_rm(int shmid)
{
return shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0);
}
After compiling Proc1.c with the -ggdb flag and running gdb I got the following:
Program received signal SIGSEGV,
Segmentation fault. 0x10a64 in main ()
at Proc1.c:36
36 Account[0]=10000
Why would this cause a segmentation fault?
After changing the declaration of Account to
int *Account = 0;
and adding
printf("Account == %p\n", Account);
before Account[0] = 10000;
I get the following upon running Proc1:
Account == ffffffff
Bus error
In order to get more sensible results from gdb you should compile your program with the -ggdb option. This will then include debugging information (like line numbers) into your program.
What you are currently seeing is the memory address (0x10a64) of the program counter. This will not help you very much unless you can correlate the assembly instructions you find there with a part of your C program yourself.
It looks like you are using shm_get properly. I think the library designer has made a terrible mistake in naming the function so similarly to shmget.
It's just as I thought. The Account pointer is ending up with an invalid value (aka 0xffffffff (aka (void *)(-1))) in it. The value (void *)(-1) generally indicates some sort of error, and it is explicitly mentioned in the manpage for shmat. This indicates that the shmat call inside the library failed. Here is how you can tell if it failed:
if (Account == (void *)(-1)) {
perror("shmat failed");
}
Account[0] = 10000;
// ...
Now, why it failed is an interesting mystery. Apparently the shmget call succeeded.
Personally, I think System V IPC is basically deprecated at this point and you should avoid using it if you can.
Depending on your compiler and your compiler options you might encounter an aliasing problem because your are casting the address of your Account pointer. These oldish interfaces are not in phase with modern antialiasing rules, meaning that the optimizer supposes that the value of Account wouldn't change.
Also you should get the argument for shm_get as close as possible to the expected type. Try perhaps something like the following.
void volatile* shmRet;
int shmid = shm_get(123456, (void**) &shmRet, 3*sizeof(int));
int *Account = shmRet;
I don't have the same architecture, so I don't know the exact prototype of your shm_get but usually it is also a bad idea to use fixed keys for this type of functions. There should be some function that returns you some key to use in your application.