What is a "callback" in C and how are they implemented? - c

From the reading that I have done, Core Audio relies heavily on callbacks (and C++, but that's another story).
I understand the concept (sort of) of setting up a function that is called by another function repeatedly to accomplish a task. I just don't understand how they get set up and how they actually work. Any examples would be appreciated.

There is no "callback" in C - not more than any other generic programming concept.
They're implemented using function pointers. Here's an example:
void populate_array(int *array, size_t arraySize, int (*getNextValue)(void))
{
for (size_t i=0; i<arraySize; i++)
array[i] = getNextValue();
}
int getNextRandomValue(void)
{
return rand();
}
int main(void)
{
int myarray[10];
populate_array(myarray, 10, getNextRandomValue);
...
}
Here, the populate_array function takes a function pointer as its third parameter, and calls it to get the values to populate the array with. We've written the callback getNextRandomValue, which returns a random-ish value, and passed a pointer to it to populate_array. populate_array will call our callback function 10 times and assign the returned values to the elements in the given array.

Here is an example of callbacks in C.
Let's say you want to write some code that allows registering callbacks to be called when some event occurs.
First define the type of function used for the callback:
typedef void (*event_cb_t)(const struct event *evt, void *userdata);
Now, define a function that is used to register a callback:
int event_cb_register(event_cb_t cb, void *userdata);
This is what code would look like that registers a callback:
static void my_event_cb(const struct event *evt, void *data)
{
/* do stuff and things with the event */
}
...
event_cb_register(my_event_cb, &my_custom_data);
...
In the internals of the event dispatcher, the callback may be stored in a struct that looks something like this:
struct event_cb {
event_cb_t cb;
void *data;
};
This is what the code looks like that executes a callback.
struct event_cb *callback;
...
/* Get the event_cb that you want to execute */
callback->cb(event, callback->data);

A simple call back program. Hope it answers your question.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include "../../common_typedef.h"
typedef void (*call_back) (S32, S32);
void test_call_back(S32 a, S32 b)
{
printf("In call back function, a:%d \t b:%d \n", a, b);
}
void call_callback_func(call_back back)
{
S32 a = 5;
S32 b = 7;
back(a, b);
}
S32 main(S32 argc, S8 *argv[])
{
S32 ret = SUCCESS;
call_back back;
back = test_call_back;
call_callback_func(back);
return ret;
}

A callback function in C is the equivalent of a function parameter / variable assigned to be used within another function.Wiki Example
In the code below,
#include <stdio.h>
#include <stdlib.h>
/* The calling function takes a single callback as a parameter. */
void PrintTwoNumbers(int (*numberSource)(void)) {
printf("%d and %d\n", numberSource(), numberSource());
}
/* A possible callback */
int overNineThousand(void) {
return (rand() % 1000) + 9001;
}
/* Another possible callback. */
int meaningOfLife(void) {
return 42;
}
/* Here we call PrintTwoNumbers() with three different callbacks. */
int main(void) {
PrintTwoNumbers(&rand);
PrintTwoNumbers(&overNineThousand);
PrintTwoNumbers(&meaningOfLife);
return 0;
}
The function (*numberSource) inside the function call PrintTwoNumbers is a function to "call back" / execute from inside PrintTwoNumbers as dictated by the code as it runs.
So if you had something like a pthread function you could assign another function to run inside the loop from its instantiation.

A callback in C is a function that is provided to another function to "call back to" at some point when the other function is doing its task.
There are two ways that a callback is used: synchronous callback and asynchronous callback. A synchronous callback is provided to another function which is going to do some task and then return to the caller with the task completed. An asynchronous callback is provided to another function which is going to start a task and then return to the caller with the task possibly not completed.
Synchronous callback
A synchronous callback is typically used to provide a delegate to another function to which the other function delegates some step of the task. Classic examples of this delegation are the functions bsearch() and qsort() from the C Standard Library. Both of these functions take a callback which is used during the task the function is providing so that the type of the data being searched, in the case of bsearch(), or sorted, in the case of qsort(), does not need to be known by the function being used.
For example, here is a small sample program with bsearch() using different comparison functions, demonstrating synchronous callbacks. By allowing us to delegate the data comparison to a callback function, the bsearch() function allows us to decide at run time what kind of comparison we want to use. This is synchronous because when the bsearch() function returns the task is complete.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int iValue;
int kValue;
char label[6];
} MyData;
int cmpMyData_iValue (MyData *item1, MyData *item2)
{
if (item1->iValue < item2->iValue) return -1;
if (item1->iValue > item2->iValue) return 1;
return 0;
}
int cmpMyData_kValue (MyData *item1, MyData *item2)
{
if (item1->kValue < item2->kValue) return -1;
if (item1->kValue > item2->kValue) return 1;
return 0;
}
int cmpMyData_label (MyData *item1, MyData *item2)
{
return strcmp (item1->label, item2->label);
}
void bsearch_results (MyData *srch, MyData *found)
{
if (found) {
printf ("found - iValue = %d, kValue = %d, label = %s\n", found->iValue, found->kValue, found->label);
} else {
printf ("item not found, iValue = %d, kValue = %d, label = %s\n", srch->iValue, srch->kValue, srch->label);
}
}
int main ()
{
MyData dataList[256] = {0};
{
int i;
for (i = 0; i < 20; i++) {
dataList[i].iValue = i + 100;
dataList[i].kValue = i + 1000;
sprintf (dataList[i].label, "%2.2d", i + 10);
}
}
// ... some code then we do a search
{
MyData srchItem = { 105, 1018, "13"};
MyData *foundItem = bsearch (&srchItem, dataList, 20, sizeof(MyData), cmpMyData_iValue );
bsearch_results (&srchItem, foundItem);
foundItem = bsearch (&srchItem, dataList, 20, sizeof(MyData), cmpMyData_kValue );
bsearch_results (&srchItem, foundItem);
foundItem = bsearch (&srchItem, dataList, 20, sizeof(MyData), cmpMyData_label );
bsearch_results (&srchItem, foundItem);
}
}
Asynchronous callback
An asynchronous callback is different in that when the called function to which we provide a callback returns, the task may not be completed. This type of callback is often used with asynchronous I/O in which an I/O operation is started and then when it is completed, the callback is invoked.
In the following program we create a socket to listen for TCP connection requests and when a request is received, the function doing the listening then invokes the callback function provided. This simple application can be exercised by running it in one window while using the telnet utility or a web browser to attempt to connect in another window.
I lifted most of the WinSock code from the example Microsoft provides with the accept() function at https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526(v=vs.85).aspx
This application starts a listen() on the local host, 127.0.0.1, using port 8282 so you could use either telnet 127.0.0.1 8282 or http://127.0.0.1:8282/.
This sample application was created as a console application with Visual Studio 2017 Community Edition and it is using the Microsoft WinSock version of sockets. For a Linux application the WinSock functions would need to be replaced with the Linux alternatives and the Windows threads library would use pthreads instead.
#include <stdio.h>
#include <winsock2.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
// Need to link with Ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
// function for the thread we are going to start up with _beginthreadex().
// this function/thread will create a listen server waiting for a TCP
// connection request to come into the designated port.
// _stdcall modifier required by _beginthreadex().
int _stdcall ioThread(void (*pOutput)())
{
//----------------------
// Initialize Winsock.
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
printf("WSAStartup failed with error: %ld\n", iResult);
return 1;
}
//----------------------
// Create a SOCKET for listening for
// incoming connection requests.
SOCKET ListenSocket;
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListenSocket == INVALID_SOCKET) {
wprintf(L"socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
struct sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(8282);
if (bind(ListenSocket, (SOCKADDR *)& service, sizeof(service)) == SOCKET_ERROR) {
printf("bind failed with error: %ld\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
//----------------------
// Listen for incoming connection requests.
// on the created socket
if (listen(ListenSocket, 1) == SOCKET_ERROR) {
printf("listen failed with error: %ld\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
//----------------------
// Create a SOCKET for accepting incoming requests.
SOCKET AcceptSocket;
printf("Waiting for client to connect...\n");
//----------------------
// Accept the connection.
AcceptSocket = accept(ListenSocket, NULL, NULL);
if (AcceptSocket == INVALID_SOCKET) {
printf("accept failed with error: %ld\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
else
pOutput (); // we have a connection request so do the callback
// No longer need server socket
closesocket(ListenSocket);
WSACleanup();
return 0;
}
// our callback which is invoked whenever a connection is made.
void printOut(void)
{
printf("connection received.\n");
}
#include <process.h>
int main()
{
// start up our listen server and provide a callback
_beginthreadex(NULL, 0, ioThread, printOut, 0, NULL);
// do other things while waiting for a connection. In this case
// just sleep for a while.
Sleep(30000);
}

Callbacks in C are usually implemented using function pointers and an associated data pointer. You pass your function on_event() and data pointers to a framework function watch_events() (for example). When an event happens, your function is called with your data and some event-specific data.
Callbacks are also used in GUI programming. The GTK+ tutorial has a nice section on the theory of signals and callbacks.

This wikipedia article has an example in C.
A good example is that new modules written to augment the Apache Web server register with the main apache process by passing them function pointers so those functions are called back to process web page requests.

It is lot easier to understand an idea through example.
What have been told about callback function in C so far are great answers, but probably the biggest benefit of using the feature is to keep the code clean and uncluttered.
Example
The following C code implements quick sorting.
The most interesting line in the code below is this one, where we can see the callback function in action:
qsort(arr,N,sizeof(int),compare_s2b);
The compare_s2b is the name of function which qsort() is using to call the function. This keeps qsort() so uncluttered (hence easier to maintain). You just call a function by name from inside another function (of course, the function prototype declaration, at the least, must precde before it can be called from another function).
The Complete Code
#include <stdio.h>
#include <stdlib.h>
int arr[]={56,90,45,1234,12,3,7,18};
//function prototype declaration
int compare_s2b(const void *a,const void *b);
int compare_b2s(const void *a,const void *b);
//arranges the array number from the smallest to the biggest
int compare_s2b(const void* a, const void* b)
{
const int* p=(const int*)a;
const int* q=(const int*)b;
return *p-*q;
}
//arranges the array number from the biggest to the smallest
int compare_b2s(const void* a, const void* b)
{
const int* p=(const int*)a;
const int* q=(const int*)b;
return *q-*p;
}
int main()
{
printf("Before sorting\n\n");
int N=sizeof(arr)/sizeof(int);
for(int i=0;i<N;i++)
{
printf("%d\t",arr[i]);
}
printf("\n");
qsort(arr,N,sizeof(int),compare_s2b);
printf("\nSorted small to big\n\n");
for(int j=0;j<N;j++)
{
printf("%d\t",arr[j]);
}
qsort(arr,N,sizeof(int),compare_b2s);
printf("\nSorted big to small\n\n");
for(int j=0;j<N;j++)
{
printf("%d\t",arr[j]);
}
exit(0);
}

Usually this can be done by using a function pointer, that is a special variable that points to the memory location of a function. You can then use this to call the function with specific arguments. So there will probably be a function that sets the callback function. This will accept a function pointer and then store that address somewhere where it can be used. After that when the specified event is triggered, it will call that function.

Related

Flutter (Dart) ffi - Aplication freezes during processing external library methohd

I am using C library iperf3 to measure network. When I start network testing my aplication freezes and wait for results. I tried async and threads but any progress. Any advise? I'd like to run my test and asynchronously call another methods (at best, call this library again, but other methods). Is it possible?
My network.dart
final DynamicLibrary iperfLib = Platform.isAndroid
? DynamicLibrary.open("libiperf.so")
: DynamicLibrary.process();
typedef RunTestFunc = ffi.Pointer<ffi.Uint8> Function(
ffi.Pointer<ffi.Uint8> context);
typedef RunTest = ffi.Pointer<ffi.Uint8> Function(
ffi.Pointer<ffi.Uint8> context);
RunTest _run_test = iperfLib
.lookup<ffi.NativeFunction<RunTestFunc>>('run_test')
.asFunction<RunTest>();
ffi.Pointer<ffi.Uint8> runTest(ffi.Pointer<ffi.Uint8> context) {
return _run_test(context);
}
and iperf.c
Iperf* run_test(Iperf* test) {
__android_log_print( ANDROID_LOG_INFO, "DONE ", "server_hostname %s", test->server_hostname );
int cc = iperf_run_client( test ) ;
__android_log_print( ANDROID_LOG_INFO, "DONE ", " %d",cc );
iperf_free_test( test );
return test
}
Async Callbacks
The problem is that C routines called from dart are blocking and therefore congest the single existing dart isolate, consequently freezing the UI.
To work around this problem you have to open a port on the dart isolate through which your C routines can asynchronously send messages to the dart isolate. To signal to the dart compiler that this is a non-blocking operation, simply delay the completion of the function until a message on the designated port has been received.
Future<int> asyncData() async {
var receiveData;
bool receivedCallback = false;
var receivePort = ReceivePort()..listen((data) {
print('Received data from c');
receiveData = data;
receivedCallback = true;
});
var nativeSendPort = receivePort.sendPort.nativePort;
nativeTriggerFunction(nativeSendPort);
while(!receivedCallback) {
await Future.delayed(Duration(milliseconds: 100));
}
receivePort.close();
return receiveData;
}
In C, you need to create a trigger function which should ideally be as lightweight as possible, passing the port number to your C code and calling the actual function you want to execute on a different thread.
The trigger function will finish almost instantly, allowing your dart thread to do other work and as soon as the newly created thread is done, it sends its result through the native port back to the dart isolate which can pick up where it left off.
void native_trigger_function(Dart_Port port) {
pthread_t t;
Dart_Port *args = (Dart_Port *) malloc(sizeof(Dart_Port));
*args = port;
pthread_create(&t, NULL, _native_function, args);
}
void *_native_function(void *args) {
Dart_Port port = *(Dart_Port *) args;
int rc = 0;
// do some heavy work
// send return code to dart
Dart_CObject obj;
obj.type = Dart_CObject_kInt32;
obj.value.as_int32 = rc;
Dart_PostCObject_DL(port, &obj);
free(args);
pthread_exit(NULL);
}
Note: This logic relies on the native dart api to work which can be found here. Before use, the interface needs to be attached to the current dart isolate which can be achieved by calling Dart_InitializeApiDL(dart_api_data) from C where dart_api_data is a void pointer which can be obtained from your dart code using the dart:ffi package through NativeApi.initializeApiData.
Update: Thanks #fdollack for fixing the example snippets!
Thank you #Lucas Aschenbach!
This minimum example was so hard to find.
2 small additions.
First, the allocated pointer should be casted to (Dart_Port*),
and the port argument from dart has to be assigned/copied to where the pointer is at!
void native_trigger_function(Dart_Port port) {
pthread_t t;
Dart_Port *args= (Dart_Port*)malloc(sizeof(Dart_Port));
*args = port; // assign port
pthread_create(&t, NULL, _native_function, args);
}
The second thing is inside the _native_function the response to Dart has to be
Dart_PostCObject_DL(port, &obj);
instead of
Dart_PostCObject_DL(args_c.send_port, &obj);

How to send messages in PM server Minix

So I'm trying to create a new system call on PM server. My question is, how can I send some kind of message to function.
in IPC server all I had to do is add my system call to the list, because all functions there were defined as (*func)(message *)
(...)/servers/ipc/main.c
static struct {
int type;
int (*func)(message *);
int reply; /* whether the reply action is passed through */
} ipc_calls[] = {
(...)
{ IPC_MYNEWSIGNAL, do_something, 1 },
};
but in PM in table.c functions are defined as
(...)/servers/pm/table.c
int (* const call_vec[NR_PM_CALLS])(void) = {
(...)
CALL(PM_GETSYSINFO) = do_getsysinfo
}
and if I try to pass function with signature
int do_something(message *m)
I will get error:
Incompatible pointer types: initializing int (*const)(void) with int (message *)
What is the correct way to create signal on PM server if I need to receive some kind of information?
As far as I understood from the question, you want to receive arguments inside the syscall handler. Let's take as an example the library function clock_settime from libc.
int clock_settime(clockid_t clock_id, const struct timespec *ts)
{
message m;
memset(&m, 0, sizeof(m));
m.m_lc_pm_time.clk_id = clock_id;
m.m_lc_pm_time.now = 1; /* set time immediately. don't use adjtime() method. */
m.m_lc_pm_time.sec = ts->tv_sec;
m.m_lc_pm_time.nsec = ts->tv_nsec;
if (_syscall(PM_PROC_NR, PM_CLOCK_SETTIME, &m) < 0)
return -1;
return 0;
}
As you can see it writes the args inside message struct and passes to _syscall. OK, now have a look at syscall handler for PM_CLOCK_SETTIME which is mounted in table.c.
int do_gettime()
{
clock_t ticks, realtime, clock;
time_t boottime;
int s;
if ( (s=getuptime(&ticks, &realtime, &boottime)) != OK)
panic("do_time couldn't get uptime: %d", s);
switch (m_in.m_lc_pm_time.clk_id) {
case CLOCK_REALTIME:
clock = realtime;
break;
case CLOCK_MONOTONIC:
clock = ticks;
break;
default:
return EINVAL; /* invalid/unsupported clock_id */
}
mp->mp_reply.m_pm_lc_time.sec = boottime + (clock / system_hz);
mp->mp_reply.m_pm_lc_time.nsec =
(uint32_t) ((clock % system_hz) * 1000000000ULL / system_hz);
return(OK);
}
It becomes clear that the argument is a global variable named m_in. A little bit more search shows that it comes from glo.h
/* The parameters of the call are kept here. */
EXTERN message m_in; /* the incoming message itself is kept here. */
I suppose that MINIX will handle setting and accessing the global variable, so you don't need to explicitly write to it.
Have a look at point 7 Passing a parameter to a system call here. To understand how to compile the kernel correctly refer to this post.

How can I create a function object in C

I would like to create a wrapper for c functions, so that I can convert a function call of the form ret = function(arg1,arg2,arg3); into the form /*void*/ function_wrapper(/*void*/);. That is similar to function objects in C++ and boost bind.
Is this possible? how can I do it?
Update:
To explain in more details what I am looking for:
We start with this function:
int f(int i){
//do stuff
return somevalue;
}
Obvioulsy, it is called like this:
// do stuff
int x = 0;
ret = f(0);
// do more stuff.
I would like to do some magic that will wrap the function into void function(void)
struct function_object fo;
fo.function_pointer = &f;
fo.add_arg(x, int);
fo.set_ret_pointer(&ret);
fo.call();
Note: I saw that there was a vote for closing this question and marking it as unclear. Please do not do that. I have a legitimate need to get this question answered. If you need explanation, ask and I will be glad to elaborate.
I came up with a better code that might allow you to do what you want. First I'll explain how it works, show the code and explain why I still don't think it's a good idea to use it (though the code might open doors for improvements that addresses those issues).
Functionality:
Before you start using the "function objects", you have to call an initialization function (FUNCTIONOBJ_initialize();), which will initialize the mutexes on every data structure used in the library.
After initializing, every time you want to call one of those "function objects", without using the parameters, you will have to set it up first. This is done by creating a FUNCTIONOBJ_handler_t pointer and calling get_function_handler(). This will search for a free FUNCTIONOBJ_handler data structure that can be used at the moment.
If none is found (all FUNCTIONOBJ_handler data structures are busy, being used by some function call) NULL is returned.
If get_function_handler() does find a FUNCTIONOBJ_handler data structure it will try to lock the FUNCTIONOBJ_id_holder data structure, that holds the ID of the FUNCTIONOBJ_handler of the function about to be called.
If FUNCTIONOBJ_id_holder is locked already, get_function_handler() will hang until it's unlocked by the thread using it.
Once FUNCTIONOBJ_id_holder is locked, the ID of the grabbed FUNCTIONOBJ_handler is wrote on it and the FUNCTIONOBJ_handler pointer is returned by get_function_handler.
With the pointer in hand, the user can set the pointer to the arguments and the return variable with set_args_pointer and set_return_pointer, which both take a void * as arguments.
Finally, you can call the function you want. It has to:
1 - Grab the FUNCTIONOBJ_handler ID from the FUNCTIONOBJ_id_holder data structure and use it to get a pointer to the FUNCTIONOBJ_handler itself.
2 - Use the FUNCTIONOBJ_handler to access the arguments.
3 - Return by using one of the return function (on the example we have ret_int, which will return an integer and unlock the FUNCTIONOBJ_handler)
Below is a simplified mind map describing a bit of what is going on:
Finally, the code:
funcobj.h:
#include <stdio.h>
#include <pthread.h>
#define MAX_SIMULTANEOUS_CALLS 1024
typedef struct {
//Current ID about to be called
int current_id;
//Mutex
pthread_mutex_t id_holder_mutex;
} FUNCTIONOBJ_id_holder_t;
typedef struct {
//Attributes
void *arguments;
void *return_pointer;
//Mutex
pthread_mutex_t handler_mutex;
} FUNCTIONOBJ_handler_t;
FUNCTIONOBJ_handler_t FUNCTIONOBJ_handler[MAX_SIMULTANEOUS_CALLS];
FUNCTIONOBJ_id_holder_t FUNCTIONOBJ_id_holder;
void set_return_pointer(FUNCTIONOBJ_handler_t *this, void *pointer);
void set_args_pointer(FUNCTIONOBJ_handler_t *this, void *pointer);
void ret_int(FUNCTIONOBJ_handler_t *this, int return_value);
void FUNCTIONOBJ_initialize(void);
FUNCTIONOBJ_handler_t *get_function_handler(void);
funcobj.c:
#include "funcobj.h"
void set_return_pointer(FUNCTIONOBJ_handler_t *this, void *pointer){
this->return_pointer = pointer;
}
void set_args_pointer(FUNCTIONOBJ_handler_t *this, void *pointer){
this->arguments = pointer;
}
void ret_int(FUNCTIONOBJ_handler_t *this, int return_value){
if(this->return_pointer){
*((int *) (this->return_pointer)) = return_value;
}
pthread_mutex_unlock(&(this->handler_mutex));
}
void FUNCTIONOBJ_initialize(void){
for(int i = 0; i < MAX_SIMULTANEOUS_CALLS; ++i){
pthread_mutex_init(&FUNCTIONOBJ_handler[i].handler_mutex, NULL);
}
pthread_mutex_init(&FUNCTIONOBJ_id_holder.id_holder_mutex, NULL);
}
FUNCTIONOBJ_handler_t *get_function_handler(void){
int i = 0;
while((0 != pthread_mutex_trylock(&FUNCTIONOBJ_handler[i].handler_mutex)) && (i < MAX_SIMULTANEOUS_CALLS)){
++i;
}
if(i >= MAX_SIMULTANEOUS_CALLS){
return NULL;
}
//Sets the ID holder to hold this ID until the function is called
pthread_mutex_lock(&FUNCTIONOBJ_id_holder.id_holder_mutex);
FUNCTIONOBJ_id_holder.current_id = i;
return &FUNCTIONOBJ_handler[i];
}
main.c:
#include "funcobj.h"
#include <string.h>
//Function:
void print(void){
//First the function must grab the handler that contains all its attributes:
//The FUNCTIONOBJ_id_holder is mutex locked, so we can just access its value and
//then free the lock:
FUNCTIONOBJ_handler_t *this = &FUNCTIONOBJ_handler[FUNCTIONOBJ_id_holder.current_id];
//We dont need the id_holder anymore, free it!
pthread_mutex_unlock(&FUNCTIONOBJ_id_holder.id_holder_mutex);
//Do whatever the function has to do
printf("%s\n", (char *) this->arguments);
//Return the value to the pointed variable using the function that returns an int
ret_int(this, 0);
}
void *thread_entry_point(void *data){
int id = (int) data;
char string[100];
snprintf(string, 100, "Thread %u", id);
int return_val;
FUNCTIONOBJ_handler_t *this;
for(int i = 0; i < 200; ++i){
do {
this = get_function_handler();
} while(NULL == this);
set_args_pointer(this, string);
set_return_pointer(this, &return_val);
print();
}
return NULL;
}
int main(int argc, char **argv){
//Initialize global data strucutres (set up mutexes)
FUNCTIONOBJ_initialize();
//testing with 20 threads
pthread_t thread_id[20];
for(int i = 0; i < 20; ++i){
pthread_create(&thread_id[i], NULL, &thread_entry_point, (void *) i);
}
for(int i = 0; i < 20; ++i){
pthread_join(thread_id[i], NULL);
}
return 0;
}
To compile: gcc -o program main.c funcobj.c -lpthread
Reasons to avoid it:
By using this, you are limiting the number of "function objects" that can be running simultaneously. That's because we need to use global data structures to hold the information required by the functions (arguments and return pointer).
You will be seriously slowing down the program when using multiple threads if those use "function objects" frequently: Even though many functions can run at the same time, only a single function object can be set up at a time. So at least for that fraction of time it takes for the program to set up the function and actually call it, all other threads trying to run a function will be hanging waiting the the data structure to be unlocked.
You still have to write some non-intuitive code at the beginning and end of each function you want to work without arguments (grabbing the FUNCTIONOBJ_handler structure, unlocking the FUNCTIONOBJ_id_holder structure, accessing arguments through the pointer you grabbed and returning values with non-built-in functions). This increases the chances of bugs drastically if care is not taken, specially some nasty ones:
Increases the chances of deadlocks. If you forget to unlock one of the data structures in any point of your code, you might end up with a program that works fine at some moments, but randomly freeze completely at others (because all function calls without arguments will be hanging waiting for the lock to be freed). That is a risk that happens on multithreaded programs anyways, but by using this you are increasing the amount of code that requires locks unnecessarily (for style purposes).
Complicates the use of recursive functions: Every time you call the function object you'll have to go through the set up phrase (even when inside another function object). Also, if you call the recursive function enough times to fill all FUNCTIONOBJ_handler structures the program will deadlock.
Amongst other reasons I might not notice at the moment :p

How can I catch the timeout exception in a third dll function,I use c language in Windows

How can I catch the timeout exception in a third dll function,I use c language in Windows
I want to catch a timeout Exception while call a thirdly dll function, you know the function takes a long while, and I need it return a value in limited time, if it doesn't return in the time, I will give it a default value.
I have to look for so much infomation about but it doesn't work.
I get the two point:
1.use the alarm function in ,but it only work in Linux,I can't use it in Windows even I use the MinGW standerd GCC complier.
2.use the timeSetEvent function in and the setjmp/longjmp function in ,the three function maybe so closed to take it work.but I use them caused the programe dump,windows pops a DialogMessage say something wrong.
I give the code and the picture like this :
`
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <setjmp.h>
jmp_buf j;
/**
* 时间中断函数
*/
void PASCAL OneMilliSecondProc(UINT wTimerID, UINT msg, DWORD dwUser, DWORD dwl, DWORD dw2) {
printf("Timout!\n");
longjmp(j,1);
}
int longTimeFunction(){
while (1) {
printf("operating...\n");
Sleep(1000);
}
return 0;
}
int main(){
HANDLE hHandle;
UINT wTimerRes_1ms;//定义时间间隔
UINT wAccuracy; //定义分辨率
UINT TimerID_1ms; //定义定时器句柄
wTimerRes_1ms = 5000;
if((TimerID_1ms = timeSetEvent(
wTimerRes_1ms,
wAccuracy,
(LPTIMECALLBACK)OneMilliSecondProc, // 回调函数
(DWORD)(1), // 用户传送到回调函数的数据;
TIME_PERIODIC//周期调用定时处理函数
)) == 0) {
printf("start!!!!!!!!!!!\n");
} else {
printf("end!!!!!!!!!!!\n");
}
int temp = 0;
if(setjmp(j) == 0){
temp = longTimeFunction();
}else{
printf("xxxxxx...\n");
temp = -1;
}
printf("%d\n", temp);
return 0;
}
`
Unlike UNIX signals, timeSetEvent doesn't interrupt a thread, the callback runs in parallel and longjmping across threads is undefined behavior.
Concerning your actual question, this is a bad idea. Such an abortion could leave the library in an inconsistent state.
Instead, try to get the library vendor to offer an API that accepts a timeout, or use another library that already supports it.

switching up/down the stack with getcontext/setcontext

I am trying to understand if getcontext/setcontext will work correctly in a specific scenario.
I can see how setcontext() can be used to unwind the stack back to a certain place in history.
#include <stdio.h>
#include <ucontext.h>
int rollback = 0;
ucontext_t context;
void func(void)
{
setcontext(cp);
}
int main(void)
{
getcontext(&context);
if (rollback == 0)
{
printf("getcontext has been called\n");
rollback++;
func();
}
else
{
printf("setcontext has been called\n");
}
}
But I was wondering if after an unwind you can re-wind back to a place that was in the future? I suppose this depends on the getcontext() call captures a copy of the stack and I can't find the exact details in the documentation.
#include <stdio.h>
#include <ucontext.h>
int rollback = 0;
int backToFuture = 0;
ucontext_t context;
ucontext_t futureContext;
void func(void)
{
// Some complex calc
if (some-condition)
{
getcontext(&futureContext); // After returning I want to come back
// here to carry on with my work.
if (backToFuture == 0)
{
setcontext(&context); // rewind to get stuff-done
}
}
// Finishe work
}
int main(void)
{
getcontext(&context);
if (rollback == 0)
{
printf("getcontext has been called\n");
rollback++;
func();
// eventually always return here.
}
else
{
printf("setcontext has been called\n");
// Do specialized work that needed to be done
// May involve function calls.
//
// I worry that anything the adds new stack frames
// will disrupt the saved state of futureContext
//
// But without detailed information I can not be sure
// if this is an allowed senario.
backToFuture = 1;
setcontext(&futureContext);
}
}
getcontext doesn't copy stack, it only dumps registers (including stack pointer) and a little context data like signal mask, etc.
When you jump down the stack it invalidates the top context. Even if you won't do any function calls think about the signal handler that can execute there. If you want to jump between two stacks you need to makecontext.
I added variable that demonstrates that your code is invalid:
void func(void)
{
// Some complex calc
if (1)
{
volatile int neverChange = 1;
getcontext(&futureContext); // After returning I want to come back
// here to carry on with my work.
printf("neverchange = %d\n", neverChange);
if (backToFuture == 0)
{
setcontext(&context); // rewind to get stuff-done
}
}
// Finishe work
}
On my machine it results in:
getcontext has been called
neverchange = 1
setcontext has been called
neverchange = 32767

Resources