Related
Suppose I create a named pipe on a Linux system:
$ mkfifo my_pipe
The next thing I want to do is write a little monitor program which tries to read() from my_pipe, but times out after a while. In the following pseudo-code, I have used a fictional function wait_for_avail(fd, timeout_ms):
int fd = open("my_pipe", O_RDONLY);
while (1) {
//Fictional wait_for_avail(fd, timeout_ms). Is there a real function
//that has this behaviour?
int rc = wait_for_avail(fd, 500);
if (rc == 1) {
char buf[64];
read(fd, buf, 64);
//do something with buf
} else {
fprintf(stderr, "Timed out while reading from my_pipe\n");
//do something else in the program
}
}
I thought poll with the POLLIN flag might work, but it does not. From my simple trials, I have found that it simply waits until another process has opened the named pipe for writing (but not for data to be available, i.e. read() would not block). By the way, for some reason, poll ignores your timeout and just seems to block forever until another process opens the pipe.
The only other solution I can think of is to open() the file with O_NONBLOCK, and sort of manually watch the time going by as I constantly try read()ing with a count of 0 bytes.
Is there a better solution out there?
EDIT: The process I have here blocks on opening the named pipe. However, if you use the O_NONBLOCK flag, the file opens right away. At that point, poll() can be used to wait (with an optional timeout) for the other end of the pipe to be opened for writing.
However, this still does have the behaviour of implementing a timeout for the read() function. It still appears to block as soon as you call read() (even if the pipe was opened with O_NONBLOCK)
Your idea about opening the fifo in non-blocking mode is correct. If you do that, poll()/select()/etc. can be used to wait for the other end to be opened, or timeout first.
The following example program just runs in an infinite loop waiting for other programs to write to my_pipe and echos the written text, with the occasional status update when there's no data or writer:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
while (1) {
int fd = open("my_pipe", O_RDONLY | O_NONBLOCK);
if (fd < 0) {
perror("open");
return EXIT_FAILURE;
}
struct pollfd waiter = {.fd = fd, .events = POLLIN};
while (1) {
// 10 second timeout
switch (poll(&waiter, 1, 10 * 1000)) {
case 0:
puts("The fifo timed out.");
break;
case 1:
if (waiter.revents & POLLIN) {
char buffer[BUFSIZ];
ssize_t len = read(fd, buffer, sizeof buffer - 1);
if (len < 0) {
perror("read");
return EXIT_FAILURE;
}
buffer[len] = '\0';
printf("Read: %s\n", buffer);
} else if (waiter.revents & POLLERR) {
puts("Got a POLLERR");
return EXIT_FAILURE;
} else if (waiter.revents & POLLHUP) {
// Writer closed its end
goto closed;
}
break;
default:
perror("poll");
return EXIT_FAILURE;
}
}
closed:
if (close(fd) < 0) {
perror("close");
return EXIT_FAILURE;
}
}
}
After a lot of help and patience from #Shawn, I managed to come up with an answer I found satisfying. Here are the contents of a file called pipe_watcher.c:
#include <stdio.h> //printf etc.
#include <errno.h> //errno
#include <string.h> //perror
#include <signal.h> //SIGALRM, sigaction, sigset
#include <time.h> //timer_create, timer_settime
#include <fcntl.h> //open, O_RDONLY
#include <unistd.h> //close
/* This code demonstrates how you can monitor a named pipe with timeouts on the
* read() system call.
*
* Compile with:
*
* gcc -o pipe_watcher pipe_watcher.c -lrt
*
* And run with:
*
* ./pipe_watcher PIPE_FILENAME
*/
//Just needed a dummy handler
void sigalrm_handler(int s) {
return;
}
int main(int argc, char **argv) {
//Check input argument count
if (argc != 2) {
puts("Usage:\n");
puts("\t./pipe_watcher PIPE_FILENAME");
return -1;
}
//Create a timer object
timer_t clk;
int rc = timer_create(CLOCK_REALTIME, NULL, &clk);
if (rc < 0) {
perror("Could not create CLOCK_REALTIME timer");
return -1;
}
//Create some time values for use with timer_settime
struct itimerspec half_second = {
.it_interval = {.tv_sec = 0, .tv_nsec = 0},
.it_value = {.tv_sec = 0, .tv_nsec = 500000000}
};
struct itimerspec stop_timer = {
.it_interval = {.tv_sec = 0, .tv_nsec = 0},
.it_value = {.tv_sec = 0, .tv_nsec = 0}
};
//Set up SIGALRM handler
struct sigaction sigalrm_act = {
.sa_handler = sigalrm_handler,
.sa_flags = 0
};
sigemptyset(&sigalrm_act.sa_mask);
rc = sigaction(SIGALRM, &sigalrm_act, NULL);
if (rc < 0) {
perror("Could not register signal handler");
timer_delete(clk);
return -1;
}
//We deliberately omit O_NONBLOCK, since we want blocking behaviour on
//read(), and we're willing to tolerate dealing with the blocking open()
int fd = open(argv[1], O_RDONLY);
if (fd < 0) {
char msg[80];
sprintf(msg, "Could not open [%s]", argv[1]);
perror(msg);
timer_delete(clk);
return -1;
}
puts("File opened");
while (1) {
//Buffer to read() into
char buf[80];
int len;
//Set up a timer to interrupt the read() call after 0.5 seconds
timer_settime(clk, 0, &half_second, NULL);
//Issue read() system call
len = read(fd, buf, 80);
//Check for errors. The else-if checks for EOF
if (len < 0) {
if (errno == EINTR) {
//This means we got interrupted by the timer; we can keep going
fprintf(stderr, "Timeout, trying again\n");
continue;
} else {
//Something really bad happened. Time to quit.
perror("read() failed");
//No point waiting for the timer anymore
timer_settime(clk, 0, &stop_timer, NULL);
break;
}
} else if (len == 0) {
puts("Reached end of file");
break;
}
//No error or EOF; stop the timer and print the results
timer_settime(clk, 0, &stop_timer, NULL);
write(STDOUT_FILENO, buf, len);
}
//Cleanup after ourselves
timer_delete(clk);
close(fd);
return 0;
}
The technique is to set up a timer before a (blocking) read() call. Then, we can simply check the return value of read() to see if it was interrupted due to a timeout, if a general error occurred, if EOF was reached, or if it successfully read data.
There's only one snag: you can't open the file in non-blocking mode; this causes open() to block until another process opens the pipe for writing. However, in my application this is actually a desirable feature. You could also set up SIGALRM to enforce a timeout on the open(), or maybe do it in another thread.
In fact, this technique should work with any other system call, so I might put together a little helper library to make this pattern easier to use.
EDIT
One more thing: it is very important to not use the SA_RESTART flag when registering the signal handler. Otherwise, even if a system call is interrupted by a signal, Linux will try it again after the signal is handled.
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'm trying to teach myself about multi-threading and multi-process programming in C (Linux). I wrote a short program which spawns a new thread which goes to a routine that tries to do a blocking read from an empty FIFO, while the main thread continues and prints to STDOUT. (Note: I did create a FIFO using mkfifo newfifo in my terminal before executing the program)
I was expecting the program to print to screen "Main thread", and then block while waiting for me to put data in the FIFO. Instead, the entire process is blocked, and the message "Main thread" only prints after I've put data into the FIFO.
Am I missing something here? Shouldn't the main thread continue to run even though the spawned thread is blocked? I tried a test using fork and creating a child process and got the same result (both processes blocked by read from empty FIFO).
Code is below:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <pthread.h>
#define NEWPIPE "./newfifo"
typedef struct __attribute__ ((__packed__)) {
int reserved :30;
int threadStarted :1;
int msgRcved :1;
} Status;
void* thread_routine(int fd, char* buffer, Status* myStatus)
{
int great_success = 0;
myStatus->threadStarted = 1;
printf("Side thread\n");
great_success = read(fd, buffer, sizeof(buffer));
if (great_success < 0) {
printf("pipe failed\n");
} else {
myStatus->msgRcved = 1;
}
}
void main()
{
int fd;
int cnt = 0;
char buffer[20];
Status* myStatus;
pthread_t thread_id;
myStatus = (Status*) malloc(sizeof(Status));
myStatus->reserved = 0;
myStatus->threadStarted = 0;
myStatus->msgRcved = 0;
fd = open(NEWPIPE, O_RDONLY);
pthread_create(&thread_id,
NULL,
(void *) thread_routine(fd, buffer, myStatus),
NULL);
printf("Main thread\n");
while (!myStatus->threadStarted) {
printf("Main thread: side thread started!\n");
}
while (!myStatus->msgRcved) {
sleep(1);
cnt++;
}
printf("buffer (cnt = %d): %s\n", cnt, buffer);
}
Edit: Latest Code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <pthread.h>
#define NEWPIPE "./newfifo"
struct Status {
unsigned int reserved :30;
unsigned int threadStarted :1;
unsigned int msgRcved :1;
};
void* thread_routine(void *arg)
{
int great_success = 0;
int fd;
char buffer[20];
struct Status* myStatus;
fd = open(NEWPIPE, O_RDONLY);
myStatus = arg;
myStatus->threadStarted = 1;
printf("Side thread\n");
while (1) {
great_success = read(fd, buffer, 20);
if (great_success < 0) {
printf("pipe failed\n");
} else {
printf("buffer : %s\n", buffer);
printf("great_success = %d\n", great_success);
great_success = 0;
}
}
}
void main()
{
int cnt = 0;
struct Status* myStatus;
pthread_t thread_id;
myStatus = (struct Status*) malloc(sizeof(struct Status));
myStatus->reserved = 0;
myStatus->threadStarted = 0;
myStatus->msgRcved = 0;
pthread_create(&thread_id,
NULL,
&thread_routine,
(void *) myStatus); // arguments to pass to the function!
printf("Main thread\n");
while (!myStatus->msgRcved) {
printf("Main thread: side thread started!\n");
if (myStatus->threadStarted) {
printf("spawned thread started!\n");
}
sleep(1);
}
pthread_exit(NULL);
}
You are passing the result of calling thread_routine() to pthread_create(). The arguments must all be evaluated before the call is executed, so the thread does not get created until that function returns. Probably. Because the thread_routine() does not return a (*)(void *), but pthread_create() attempts to call the return value as if it were one, the whole program's behavior is undefined. You want to pass a pointer to the function, not the result of calling it:
pthread_create(&thread_id,
NULL,
thread_routine,
NULL);
"But what about the arguments," you ask? That leads me to the next point: function thread_routine() does not have the correct signature for a thread start routine. A thread start routine must accept a single argument of type void *. The last argument to pthread_create() will be passed to the specified function as its (single) argument, and you can make that a pointer to an appropriate struct in lieu of passing multiple separate arguments.
Finally, your putative thread start function needs to exit either by returning a pointer value (possibly NULL) or by calling pthread_exit(). Behavior is undefined when a value-returning function other than main() reaches its terminal } without executing a return statement. (pthread_exit() solves that because it does not return.)
Note, by the way, that your compiler ought to have spit out several warnings about this code. You should always resolve all compiler warnings, or be certain why it's safe not to do so.
Instead, the entire process is blocked, and the message "Main thread" only prints after I've put data into the FIFO.
Am I missing something here?
Your main thread is blocked at this line:
fd = open(NEWPIPE, O_RDONLY);
because a non-blocking, read-only open of a FIFO will block until a writer is available. Your main thread is finally unblocked, not when you write data to the FIFO, but when you simply open the FIFO for writing.
There are other problems in the code as #JohnBollinger discusses in his answer. However, the FIFO semantics are why you are not seeing the initial output you expect.
the following is a way to open a named pipe,
so there is no need for any (before running application)
processing needed.
enum enumReturnStatus create_Pipe( INT32 taskSelector )
{
enum enumReturnStatus returnStatus = eRS_Success; // indicate success
char *pTask_NameString = NULL;
char Pipe_NameString[ 100 ] = {'\0'};
struct stat statInfo; // will contain info on a file
// and is used to determine if the pipe already exists
INT32 mkfifoStatus = 0;
INT32 statStatus = 0;
if( 0 >= Pipe_Parameters[ taskSelector ].Pipe_FD )
{ // then pipe not open
pTask_NameString = get_pTask_NameString( taskSelector );
if( NULL == pTask_NameString )
{ // task not configured
return( eRS_Failure );
}
/* *********************************************************************
* implied else, task configured
* ********************************************************************
*/
// create pipe name string
sprintf( Pipe_NameString, "/tmp/Pipe_2%s", pTask_NameString );
// check if pipe already exists
statStatus = stat(Pipe_NameString, &statInfo);
if( (statStatus)&&(ENOENT == errno) )
{ // then, FIFO pipe does not exist
// create the pipe
umask(0);
// maybe use mknode() instead of mkfifo()
// mknod(pPipe_name, S_IFIFO | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0 );
// 0666 allows anyone to read/write the pipe
mkfifoStatus = mkfifo( Pipe_NameString, 0666 );
if ( -1 == mkfifoStatus )
{
CommonWriteCdsLog( eLL_Critical,
get_pFormatString( eFormat_CFFL_string_string ),
__FILE__, __LINE__,
"LibFunc:mkfifo() failed to create pipe ",
strerror( errno ) );
fprintf(stderr,"mkfifo failed: %s \n",strerror( errno ));
fflush(stderr);
system( "sync; sync;" );
exit( EXIT_FAILURE );
}
} // endif ( pipe doesn't exist )
if( !mkfifoStatus && !statStatus )
{ // then pipe created or already exists
if( 0 >= Pipe_Parameters[taskSelector].Pipe_FD )
{ // then, pipe not yet open
// note: use O_RDWR so open will not hang
Pipe_Parameters[taskSelector].Pipe_FD = open( Pipe_NameString, O_CREAT|O_RDWR );
if( 0 >= Pipe_Parameters[taskSelector].Pipe_FD )
{ // then open failed
CommonWriteCdsLog( eLL_Critical,
get_pFormatString( eFormat_CFFL_string_string ),
__FILE__, __LINE__,
"LibFunc:open() failed for pipe",
strerror( errno ) );
}
else
{ // else open successful
;
} // endif( open for read successful )
} // endif( pipe not already open )
} // endif( pipe created or already exists )
} // endif( pipe not open )
return( returnStatus );
} // end create_Pipe()
This code:
typedef struct __attribute__ ((__packed__)) {
int reserved :30;
int threadStarted :1;
int msgRcved :1;
} Status;
will give problems as the code is using signed values and struct definitions should not be typedef'd as the typedef'ing:
obscures the code,
generates confusion in the reader
and clutters the compiler name space
here is an example of the preferred method to define a struct
(and correct the problem with the bit fields)
struct status
{
unsigned int reserved :30;
unsigned int threadStarted :1;
unsigned int msgRcved :1;
};
There should be no need for the packed attribute as all the bits will fit into a single unsigned int memory area. Reference this struct via: struct status in variable definitions and function parameter lists.
I am actually trying to write a small program to catch global keyboard inputs from specific USB keyboards under linux.
I am testing with this piece of code :
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <string.h>
#include <stdio.h>
static const char *const evval[3] = {
"RELEASED",
"PRESSED ",
"REPEATED"
};
int main(void)
{
const char *dev = "/dev/input/event2";
struct input_event ev;
ssize_t n;
int fd;
char name[256]= "Unknown";
// int codes[2];
// codes[0] = 58; /* M keycap */
// codes[1] = 49; /* assign to N */
fd = open(dev, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "Cannot open %s: %s.\n", dev, strerror(errno));
return EXIT_FAILURE;
}
if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) > 0)
{
printf("The device on %s says its name is '%s'\n", dev, name);
}
/*
int err = ioctl(fd, EVIOCSKEYCODE, codes);
if (err) {
perror("evdev ioctl");
}*/
while (1) {
n = read(fd, &ev, sizeof ev);
if (n == (ssize_t)-1) {
if (errno == EINTR)
continue;
else
break;
} else
if (n != sizeof ev) {
errno = EIO;
break;
}
if (ev.type == EV_KEY && ev.value >= 0 && ev.value <= 2)
printf("%s 0x%04x (%d)\n", evval[ev.value], (int)ev.code, (int)ev.code);
}
fflush(stdout);
fprintf(stderr, "%s.\n", strerror(errno));
return EXIT_FAILURE;
}
Ths point is that I don't know how to change some input key by other. I tried by calling write() on currently red event by changing the event code, sent key was still previous one, and I tried to used ioctl with EVIOCSKEYCODE, but the call failed with an "invalid argument" error (and I'm not sure to call it correctly).
How can I change outputed key correctly ?
Use the EVIOCGRAB ioctl to grab the input device, so that by reading the events you consume them. Normally (not-grabbed) the events are not consumed when you read them. The ioctl takes an additional parameter, (int)1 for grabbing, (int)0 for releasing.
To re-inject any events, just write them to the uinput device. See eg. a mouse example here. (The event structures are the same type, you only need to write a struct uinput_user_dev structure to the uinput device first, to describe your new input device (which provides the mapped events).)
In other words, you don't remap: you consume and forward.
The standard way would be the following:
if (ptrace(PTRACE_TRACEME, 0, NULL, 0) == -1)
printf("traced!\n");
In this case, ptrace returns an error if the current process is traced (e.g., running it with GDB or attaching to it).
But there is a serious problem with this: if the call returns successfully, GDB may not attach to it later. Which is a problem since I'm not trying to implement anti-debug stuff. My purpose is to emit an 'int 3' when a condition is met (e.g., an assert fails) and GDB is running (otherwise I get a SIGTRAP which stops the application).
Disabling SIGTRAP and emitting an 'int 3' every time is not a good solution because the application I'm testing might be using SIGTRAP for some other purpose (in which case I'm still screwed, so it wouldn't matter, but it's the principle of the thing :))
On Windows there is an API, IsDebuggerPresent, to check if process is under debugging. At Linux, we can check this with another way (not so efficient).
Check "/proc/self/status" for "TracerPid" attribute.
Example code:
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
bool debuggerIsAttached()
{
char buf[4096];
const int status_fd = open("/proc/self/status", O_RDONLY);
if (status_fd == -1)
return false;
const ssize_t num_read = read(status_fd, buf, sizeof(buf) - 1);
close(status_fd);
if (num_read <= 0)
return false;
buf[num_read] = '\0';
constexpr char tracerPidString[] = "TracerPid:";
const auto tracer_pid_ptr = strstr(buf, tracerPidString);
if (!tracer_pid_ptr)
return false;
for (const char* characterPtr = tracer_pid_ptr + sizeof(tracerPidString) - 1; characterPtr <= buf + num_read; ++characterPtr)
{
if (isspace(*characterPtr))
continue;
else
return isdigit(*characterPtr) != 0 && *characterPtr != '0';
}
return false;
}
The code I ended up using was the following:
int
gdb_check()
{
int pid = fork();
int status;
int res;
if (pid == -1)
{
perror("fork");
return -1;
}
if (pid == 0)
{
int ppid = getppid();
/* Child */
if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) == 0)
{
/* Wait for the parent to stop and continue it */
waitpid(ppid, NULL, 0);
ptrace(PTRACE_CONT, NULL, NULL);
/* Detach */
ptrace(PTRACE_DETACH, getppid(), NULL, NULL);
/* We were the tracers, so gdb is not present */
res = 0;
}
else
{
/* Trace failed so GDB is present */
res = 1;
}
exit(res);
}
else
{
waitpid(pid, &status, 0);
res = WEXITSTATUS(status);
}
return res;
}
A few things:
When ptrace(PTRACE_ATTACH, ...) is successful, the traced process will stop and has to be continued.
This also works when GDB is attaching later.
A drawback is that when used frequently, it will cause a serious slowdown.
Also, this solution is only confirmed to work on Linux. As the comments mentioned, it won't work on BSD.
You could fork a child which would try to PTRACE_ATTACH its parent (and then detach if necessary) and communicates the result back. It does seem a bit inelegant though.
As you mention, this is quite costly. I guess it's not too bad if assertions fail irregularly. Perhaps it'd be worthwhile keeping a single long-running child around to do this - share two pipes between the parent and the child, child does its check when it reads a byte and then sends a byte back with the status.
I had a similar need, and came up with the following alternatives
static int _debugger_present = -1;
static void _sigtrap_handler(int signum)
{
_debugger_present = 0;
signal(SIGTRAP, SIG_DFL);
}
void debug_break(void)
{
if (-1 == _debugger_present) {
_debugger_present = 1;
signal(SIGTRAP, _sigtrap_handler);
raise(SIGTRAP);
}
}
If called, the debug_break function will only interrupt if a debugger is attached.
If you are running on x86 and want a breakpoint which interrupts in the caller (not in raise), just include the following header, and use the debug_break macro:
#ifndef BREAK_H
#define BREAK_H
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int _debugger_present = -1;
static void _sigtrap_handler(int signum)
{
_debugger_present = 0;
signal(SIGTRAP, SIG_DFL);
}
#define debug_break() \
do { \
if (-1 == _debugger_present) { \
_debugger_present = 1; \
signal(SIGTRAP, _sigtrap_handler); \
__asm__("int3"); \
} \
} while(0)
#endif
I found that a modified version of the file descriptor "hack" described by Silviocesare and blogged by xorl worked well for me.
This is the modified code I use:
#include <stdio.h>
#include <unistd.h>
// gdb apparently opens FD(s) 3,4,5 (whereas a typical prog uses only stdin=0, stdout=1,stderr=2)
int detect_gdb(void)
{
int rc = 0;
FILE *fd = fopen("/tmp", "r");
if (fileno(fd) > 5)
{
rc = 1;
}
fclose(fd);
return rc;
}
If you just want to know whether the application is running under GDB for debugging purposes, the simplest solution on Linux is to readlink("/proc/<ppid>/exe"), and search the result for "gdb".
This is similar to terminus' answer, but uses pipes for communication:
#include <unistd.h>
#include <stdint.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#if !defined(PTRACE_ATTACH) && defined(PT_ATTACH)
# define PTRACE_ATTACH PT_ATTACH
#endif
#if !defined(PTRACE_DETACH) && defined(PT_DETACH)
# define PTRACE_DETACH PT_DETACH
#endif
#ifdef __linux__
# define _PTRACE(_x, _y) ptrace(_x, _y, NULL, NULL)
#else
# define _PTRACE(_x, _y) ptrace(_x, _y, NULL, 0)
#endif
/** Determine if we're running under a debugger by attempting to attach using pattach
*
* #return 0 if we're not, 1 if we are, -1 if we can't tell.
*/
static int debugger_attached(void)
{
int pid;
int from_child[2] = {-1, -1};
if (pipe(from_child) < 0) {
fprintf(stderr, "Debugger check failed: Error opening internal pipe: %s", syserror(errno));
return -1;
}
pid = fork();
if (pid == -1) {
fprintf(stderr, "Debugger check failed: Error forking: %s", syserror(errno));
return -1;
}
/* Child */
if (pid == 0) {
uint8_t ret = 0;
int ppid = getppid();
/* Close parent's side */
close(from_child[0]);
if (_PTRACE(PTRACE_ATTACH, ppid) == 0) {
/* Wait for the parent to stop */
waitpid(ppid, NULL, 0);
/* Tell the parent what happened */
write(from_child[1], &ret, sizeof(ret));
/* Detach */
_PTRACE(PTRACE_DETACH, ppid);
exit(0);
}
ret = 1;
/* Tell the parent what happened */
write(from_child[1], &ret, sizeof(ret));
exit(0);
/* Parent */
} else {
uint8_t ret = -1;
/*
* The child writes a 1 if pattach failed else 0.
*
* This read may be interrupted by pattach,
* which is why we need the loop.
*/
while ((read(from_child[0], &ret, sizeof(ret)) < 0) && (errno == EINTR));
/* Ret not updated */
if (ret < 0) {
fprintf(stderr, "Debugger check failed: Error getting status from child: %s", syserror(errno));
}
/* Close the pipes here, to avoid races with pattach (if we did it above) */
close(from_child[1]);
close(from_child[0]);
/* Collect the status of the child */
waitpid(pid, NULL, 0);
return ret;
}
}
Trying the original code under OS X, I found waitpid (in the parent) would always return -1 with an EINTR (System call interrupted). This was caused by pattach, attaching to the parent and interrupting the call.
It wasn't clear whether it was safe to just call waitpid again (that seemed like it might behave incorrectly in some situations), so I just used a pipe to do the communication instead. It's a bit of extra code, but will probably work reliably across more platforms.
This code has been tested on OS X v10.9.3 (Mavericks), Ubuntu 14.04 (Trusty Tahr) (3.13.0-24-generic) and FreeBSD 10.0.
For Linux, which implements process capabilities, this method will only work if the process has the CAP_SYS_PTRACE capability, which is typically set when the process is run as root.
Other utilities (gdb and lldb) also have this capability set as part of their filesystem metadata.
You can detect whether the process has effective CAP_SYS_PTRACE by linking against -lcap,
#include <sys/capability.h>
cap_flag_value_t value;
cap_t current;
/*
* If we're running under Linux, we first need to check if we have
* permission to to ptrace. We do that using the capabilities
* functions.
*/
current = cap_get_proc();
if (!current) {
fprintf(stderr, "Failed getting process capabilities: %s\n", syserror(errno));
return -1;
}
if (cap_get_flag(current, CAP_SYS_PTRACE, CAP_PERMITTED, &value) < 0) {
fprintf(stderr, "Failed getting permitted ptrace capability state: %s\n", syserror(errno));
cap_free(current);
return -1;
}
if ((value == CAP_SET) && (cap_get_flag(current, CAP_SYS_PTRACE, CAP_EFFECTIVE, &value) < 0)) {
fprintf(stderr, "Failed getting effective ptrace capability state: %s\n", syserror(errno));
cap_free(current);
return -1;
}
C++ version of Sam Liao's answer (Linux only):
// Detect if the application is running inside a debugger.
bool being_traced()
{
std::ifstream sf("/proc/self/status");
std::string s;
while (sf >> s)
{
if (s == "TracerPid:")
{
int pid;
sf >> pid;
return pid != 0;
}
std::getline(sf, s);
}
return false;
}