Ensure transactions all complete on SHUTDOWN hook...sample code check - c

I actually asked a similar question earlier at Correct way to shutdown C application to ensure CRITICAL sections completed? but wanted to start fresh and ask is anyone can see and FUNDAMENTAL issues with the following code.
I essentially whipped up a proof of concept, and it goes like this:
Main application launches a thread that needs to "process messages in a transaction"
When the user hits CTRL-C I need the application to run elegantly until the current thread transaction is complete
NOTE: Callbacks from the thread into the MAIN app is ESSENTIAL and I would like to know if this is "bad programming practice"....
The code is working from the output, here is a sample:
lynton#lynton ~/Desktop/ThreadTest $ ./main
Main program started
In thread testMainLoop
Transaction started in spawned thread
onBeginTransaction in main thread
onMessageArrived in main thread
onCommitTransaction in main thread
Transaction ended in spawned thread
Transaction started in spawned thread
onBeginTransaction in main thread
onMessageArrived in main thread
onCommitTransaction in main thread
Transaction ended in spawned thread
Transaction started in spawned thread
onBeginTransaction in main thread
onMessageArrived in main thread
onCommitTransaction in main thread
Transaction ended in spawned thread
^CIn shutdown hook...
Thread still running
listenForMessages loop completed in spawned thread
In onProcessingComplete in main thread
Exciting testMainLoop
All thread transactions complete
Main program exiting
lynton#lynton ~/Desktop/ThreadTest $
In the above you can see that the shutdown hook is initiated and the application ends gracefully...
The basis test code is as follows:
PLEASE take special note of the "(*onProcessingCompleteCallbackFunc)(TRUE);" call from the thread to the main application to say to the main application that the thread is 100% complete. The pthread_join did not seem to work as I needed it to here....
NOTE: The following is the SHARED LIB (libwmq_sender.so) that I created that is used by the main application.
wmq_sender.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define TRUE 0
#define FALSE 1
int wmq_sender_start();
int wmq_sender_stop();
void wmq_sender_registerOnBeginTransactionCallback(int (*callbackFunc)(char *tid));
void wmq_sender_registerOnCommitTransactionCallback(int (*callbackFunc)(char *tid));
void wmq_sender_registerOnMessageArrivedCallback(int (*callbackFunc)(char *tid, char *buffer, int size));
void wmq_sender_registerOnProcessingCompleteCallback(void (*callbackFunc)(int completeFlag));
int listenForMessages();
int (*onBeginTransactionCallbackFunc)(char *tid);
int (*onCommitTransactionCallbackFunc)(char *tid);
int (*onRollbackTransactionCallbackFunc)(char *tid);
int (*onMessageArrivedCallbackFunc)(char *tid, char *buffer, int size);
void (*onProcessingCompleteCallbackFunc)(int completeFlag);
int running;
int rc;
int transactionRunning;
wmq_sender.c
#include "wmq_sender.h"
int listenForMessages(){
char *uuid = NULL;;
char *buffer = NULL;
uuid = malloc(10 * sizeof(char));
strcpy(uuid, "1234567891");
buffer = malloc(11 * sizeof(char));
strcpy(buffer, "test_buffer");
while(running == TRUE){
printf("Transaction started in spawned thread\n");
transactionRunning = TRUE;
(*onBeginTransactionCallbackFunc)(uuid);
(*onMessageArrivedCallbackFunc)(uuid, buffer, 11);
(*onCommitTransactionCallbackFunc)(uuid);
transactionRunning = FALSE;
printf("Transaction ended in spawned thread\n");
sleep(2);
}
printf("listenForMessages loop completed in spawned thread\n");
free(uuid);
free(buffer);
(*onProcessingCompleteCallbackFunc)(TRUE);
return 0;
}
int wmq_sender_start(){
return listenForMessages();
}
int wmq_sender_stop(){
running = FALSE;
return 0;
}
void wmq_sender_registerOnBeginTransactionCallback(int (*callbackFunc)(char *tid)){
onBeginTransactionCallbackFunc = callbackFunc;
}
void wmq_sender_registerOnCommitTransactionCallback(int (*callbackFunc)(char *tid)){
onCommitTransactionCallbackFunc = callbackFunc;
}
void wmq_sender_registerOnMessageArrivedCallback(int (*callbackFunc)(char *tid, char *buffer, int size)){
onMessageArrivedCallbackFunc = callbackFunc;
}
void wmq_sender_registerOnProcessingCompleteCallback(void (*callbackFunc)(int completeFlag)){
onProcessingCompleteCallbackFunc = callbackFunc;
}
The following is the MAIN application that spawns the thread and shuts down gracefully etc.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <time.h>
#include "wmq_sender.h"
#define TRUE 0
#define FALSE 1
void *testMainLoop(void *arg);
void shutdownHook(int sig);
int main(int argc, char * argv[]);
int onBeginTransaction(char *tid);
int onCommitTransaction(char *tid);
int onMessageArrived(char *tid, char *buffer, int size);
void onProcessingComplete(int completeFlag);
pthread_t testThread;
int threadRunning;
int rc;
void *testMainLoop(void *arg){
printf("In thread testMainLoop\n");
wmq_sender_registerOnBeginTransactionCallback(onBeginTransaction);
wmq_sender_registerOnCommitTransactionCallback(onCommitTransaction);
wmq_sender_registerOnMessageArrivedCallback(onMessageArrived);
wmq_sender_registerOnProcessingCompleteCallback(onProcessingComplete);
threadRunning = TRUE;
rc = wmq_sender_start();
printf("Exciting testMainLoop\n");
}
void shutdownHook(int sig){
printf("In shutdown hook...\n");
rc = wmq_sender_stop();
while(threadRunning == TRUE){
printf("Thread still running\n");
sleep(2);
}
printf("All thread transactions complete\n");
}
void onProcessingComplete(int completeFlag){
printf("In onProcessingComplete in main thread\n");
threadRunning = FALSE;
}
int main(int argc, char * argv[]){
(void) signal(SIGINT, shutdownHook);
printf("Main program started\n");
rc = pthread_create(&testThread, NULL, testMainLoop, (void *)argv);
pthread_join(testThread, NULL);
printf("Main program exiting\n");
return 0;
}
int onBeginTransaction(char *tid){
printf("onBeginTransaction in main thread\n");
return 0;
}
int onCommitTransaction(char *tid){
printf("onCommitTransaction in main thread\n");
return 0;
}
int onMessageArrived(char *tid, char *buffer, int size){
printf("onMessageArrived in main thread\n");
return 0;
}
Compiling on my test machine is:
gcc -m64 -Wall -g -I./ -c ./main.c -o ./main.o
gcc -m64 -o ./main ./main.o -L./ -L/usr/lib -L/usr/local/lib -lpthread -lwmq_sender
gcc -m64 -Wall -g -c -I./ -I/usr/local/include/ -fPIC ./wmq_sender.c -o ./wmq_sender.o
gcc -shared -o ./libwmq_sender.so ./wmq_sender.o
export LD_LIBRARY_PATH="/home/lynton/Desktop/ThreadTest"
Do you see anything wrong with the way that I use CALLBACKS to tell the main application that the thread is complete etc?
Any help or advise would be great appreciated ;-)
Thanks
Lynton

You do realise that your callback functions are actually running on the thread don't you? As far as I can see, your main thread just creates another thread which does everything and then waits for it to finish. I don't see any point in creating the second thread at the moment.
Anyway, the other horrible problem you have is that your signal handler calls printf and sleep. I'm pretty sure printf is not safe to call in a signal handler and neither is sleep. Really all it should do is set a flag to say "terminating" and then return.
According to the C99 standard, you can't reliably assign to any static variable that isn't declared volatile sig_atomic_t or call any standard library function except abort(), _Exit() or signal() and the last with the same signal number that you received.

Related

Multithreading in C language: [I'm asking for explanation]

Can please some one explain the output of the code below!
I was working with threads in C language, and caught my eye that sometimes the output of the programs is not totally one of my prediction.
So I tried to write this code to understand more..
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
void * threadfun(void *arg){
printf("Hello from thread id %ld\n",*(pthread_t*)arg);
return NULL;
}
int main (int argc, char *argv[]){
pthread_t tid;
void * (*fp)(void*) = &threadfun;
printf("The Main program. pid = %d.\n",getpid());
pthread_create(&tid, NULL,fp,(void*)&tid);
printf("%ld was the thread id.\n",tid);
//pthread_join(tid, NULL);
printf("ENd. \n");
return 0;
}
I comment out the join function on purpose.
The output of this code was sometimes something like this:
gcc (Debian 11.2.0-10) 11.2.0
└─$ gcc s1_LD_thread01.c -o out_s1_thread01 -lpthread
└─$ ./out_s1_thread01
The Main program. pid = 8683.
140305239197248 was the thread id.
ENd.
Hello from thread id 140305239197248
Hello from thread id 140305239197248
I am wondering why the created thread outputting two strings.!

CTRL + C doesn't kill C script

I'm reading Operating Systems: Three Easy Pieces and I'm finding a problem is not mentioned in the book.
This is the C script:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
/*#include "common.h"*/
#include <unistd.h>
#include <assert.h>
int
main(int argc, char *argv[])
{
int *p = malloc(sizeof(int));
assert(p != NULL);
printf("(%d address pointed to by p: %p\n",
getpid(), p);
*p = 0;
while (1) {
sleep(1);
*p = *p +1;
printf("(%d) p: %d\n", getpid(), *p);
}
return 0;
}
It allocates some memory, prints out the address memory, puts the number 0 into it and finally loops to increment the value.
I compile it through gcc -o mem mem.c -Wall and I have no problem running it with ./mem, if I press CRTL+C it will stop:
But then problems come when I run the script twice in parallel with the command ./mem & ./mem, look at the GIF:
No matter how many times I try to kill the process the scripts keeps hammering.
How to kill my C which project?
Use fg to bring the backgrounded process to the foreground, then it will respond to Ctrl-C.
You can also use jobs to see a numbered list of backgrounded jobs, and kill %<number> to kill a specific job, e.g. kill %1.

linker error in c thread program.. ld returned 1 exit status

i was trying to learn multithreading program in c and got a linker error which I am not able to solve I have checked the previous problem similar to this but those solutions could not solve my problem.
error :
single_thread.c:(.text+0x15)undefined reference to 'thread_function'
collect2:ld returned 1 exit status
I have checked the typo's
the program goes like this
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<string.h>
void *thread_functions(void *arg);
char message[]="Hello world";
int main()
{
int res;
pthread_t a_thread;
void *thread_res;
res=pthread_create(&a_thread,NULL,thread_functions,(void*)message);
//i guess error is from the function pointer.
if(res!=0)
{
perror("thread creation:");
exit(EXIT_FAILURE);
}
printf("waiting for thread to finish...\n");
pthread_join(a_thread,NULL);
/* if(res!=0)
{
perror("thread_join failed:");
exit(EXIT_FAILURE);
}*/
// printf("thread joined,it has returned %s\n",(char*)thread_res);
printf("Message:%s\n",message);
exit(EXIT_SUCCESS);
}
void *thread_fucntions(void *arg)
{
printf("thread function is running.argument was %s\n",(char*)arg);
sleep(3);
strcpy(message,"BYE!");
pthread_exit("thank you for the cpu time");
}
You need to name the functions exactly the same as forward declaration and definition time. Your compiler sees the forward declaration of the function thread_functions() and the call to it, but during the linking time, linker does not get to see a definition of the same, as you're having a typo there. So it screams.
Change
void *thread_fucntions(void *arg)
to
void *thread_functions(void *arg)
You need to compile like this
gcc single.thread.c -lpthread
Typo
void *thread_fucntions(void *arg)
^^

pthread_cond_broadcast broken with dlsym?

I am trying to interpose calls to pthread_cond_broadcast using LD_PRELOAD mechanism. My interposed pthread_cond_broadcast function just calls the original pthread_cond_broadcast. However, for a very simple pthread code where both pthread_cond_wait and pthread_cond_broadcast get invoked, I either end up with a segfault in glibc (for glibc 2.11.1) or the program hangs (for glibc 2.15). Any clues on that is going on?
The interposition code (that gets compiled as a shared library):
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <dlfcn.h>
static int (*orig_pthread_cond_broadcast)(pthread_cond_t *cond) = NULL;
__attribute__((constructor))
static void start() {
orig_pthread_cond_broadcast =
(int (*)()) dlsym(RTLD_NEXT, "pthread_cond_broadcast");
if (orig_pthread_cond_broadcast == NULL) {
printf("pthread_cond_broadcast not found!!!\n");
exit(1);
}
}
__attribute__((__visibility__("default")))
int pthread_cond_broadcast(pthread_cond_t *cond) {
return orig_pthread_cond_broadcast(cond);
}
The simple pthread program:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t cond_mutex;
pthread_cond_t cond_var;
int condition;
void *thread0_work(void *arg) {
pthread_mutex_lock(&cond_mutex);
printf("Signal\n");
condition = 1;
pthread_cond_broadcast(&cond_var);
pthread_mutex_unlock(&cond_mutex);
return NULL;
}
void *thread1_work(void *arg) {
pthread_mutex_lock(&cond_mutex);
while (condition == 0) {
printf("Wait\n");
pthread_cond_wait(&cond_var, &cond_mutex);
printf("Done waiting\n");
}
pthread_mutex_unlock(&cond_mutex);
return NULL;
}
int main() {
pthread_t thread1;
pthread_mutex_init(&cond_mutex, NULL);
pthread_cond_init(&cond_var, NULL);
pthread_create(&thread1, NULL, thread1_work, NULL);
// Slowdown this thread, so the thread 1 does pthread_cond_wait.
usleep(1000);
thread0_work(NULL);
pthread_join(thread1, NULL);
return 0;
}
EDIT:
For glibc 2.11.1, gdb bt gives:
(gdb) set environment LD_PRELOAD=./libintercept.so
(gdb) run
Starting program: /home/seguljac/intercept/main
[Thread debugging using libthread_db enabled]
[New Thread 0x7ffff7436700 (LWP 19165)]
Wait
Signal
Before pthread_cond_broadcast
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff79ca0e7 in pthread_cond_broadcast##GLIBC_2.3.2 () from /lib/libpthread.so.0
(gdb) bt
#0 0x00007ffff79ca0e7 in pthread_cond_broadcast##GLIBC_2.3.2 () from /lib/libpthread.so.0
#1 0x00007ffff7bdb769 in pthread_cond_broadcast () from ./libintercept.so
#2 0x00000000004008e8 in thread0_work ()
#3 0x00000000004009a4 in main ()
EDIT 2:
(Solved)
As suggested by R.. (thanks!), the issue is that on my platform pthread_cond_broadcast is a versioned symbol, and dlsym gives the wrong version. This blog explains this situation in great detail: http://blog.fesnel.com/blog/2009/08/25/preloading-with-multiple-symbol-versions/
The call through your function seems to end up in a different version of the function:
With LD_PRELOAD: __pthread_cond_broadcast_2_0 (cond=0x804a060) at old_pthread_cond_broadcast.c:37
Without LD_PRELOAD: pthread_cond_broadcast##GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/i386/i686/../i486/pthread_cond_broadcast.S:39
So your situation is similar to this question, i.e. you are getting incompatible versions of pthread functions: symbol versioning and dlsym
This page gives one way to solve the problem, though a bit complex: http://blog.fesnel.com/blog/2009/08/25/preloading-with-multiple-symbol-versions/

How to start two instances of a process through fork without modifying the program

I am trying to fork a process from another at the start. For this I tried to modify the __libc_start_main function in glibc (a modified glibc that I use) and tried to put the fork there, but could not compile the glibc as it gives an error whenever I try to do that. What are other options and why inserting fork in __libc_start_main doesn't work?
Again notice that I want to do it in a way that no program modification is required, that is modification in glibc is OK but not the program.
In __libc_start_main, I try to fork like this.
if (__builtin_expect (! not_first_call, 1))
{
struct pthread *self;
fork(); // <-- here
self = THREAD_SELF;
/* Store old info. */
unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup);
/* Store the new cleanup handler info. */
THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf);
/* Run the program. */
result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
}
The error i get is the following.
file '/build/sunrpc/xbootparam_prot.T' already exists and may be overwritten
make[2]: *** [build/sunrpc/xbootparam_prot.stmp] Error 1
If you're statically linking to an unmodifiable object with the main entry point, you could use symbol wrapping to sneak the fork() before the object's main().
For example, main.o that can't be modified:
#include <stdio.h>
int main( int argc, char *argv[] ) {
printf( "In main()\n" );
return 0;
}
Your wrapper symbol within glibc:
#include <unistd.h>
#include <stdio.h>
int __wrap_main( int argc, char *argv[] ) {
printf( "In wrapper\n" );
if ( fork() ) {
return __real_main( argc, argv );
} else {
printf( "Other process did something else\n" );
return 0;
}
}
And use the --wrap command linker command:
gcc -o app main.o wrap.o -Wl,--wrap=main
$ ./app
In wrapper
In main()
$ Other process did something else

Resources