Call a proc in Ruby C extension - c

I have the following struct:
typedef struct{
int a;
int (*init)(void);
} tObj;
I am wrapping this into an object 'ObjExt' in Ruby. Ruby initialization method gets a Proc 'cb' that shall be run anytime 'init' function is called somewhere to generate an integer.
something like:
cb = Proc.new { 1 }
ruby_obj = ObjExt.new(cb)
My first shot at this was I passed the 'cb' proc to a global VALUE type variable and run rb_funcall on it in a wrapper function "int (*wrapper)(void)" that I define, and literally assign init = wrapper. but this won't work if I have multiple object instances of ObjExt class as the global variable is shared between instances and gets overwritten when initializing the second and third objects.
Any hints would be appreciated. I am probably approaching the problem in a wrong way.

Related

Class approximation in C - Is this witchcraft or technically acceptable?

I need to do a large Project in C and C only, without external librairies (except for SDL).
I started looking for ways to do some kind of class in C, what led me to that :
typedef void (*voidFunction)(void);
typedef struct{
int id;
voidFunction printId;
} Object;
Object *new_Object(int id){
Object *newObject = malloc(sizeof(Object));
newObject->id = id;
void printId(){
static Object *this = NULL;
if(!this) this = newObject;
printf("%d\n", this->id);
};
newObject->printId = printId;
return newObject;
}
int main(){
Object *object = new_Object(5);
object->printId();
object->id++;
object->printId();
return 0;
}
Output of main :
5
6
So this works, but does it seems reasonable ?
Should I expect a backlash if I use this kind of architecture for a big project? Maybe I'm typing out of my allocated memory without realizing it?
Techniques for implementing polymorphism in C are long established, check this answer for instance https://stackoverflow.com/a/351745/4433969
Your implementation seems to be broken. Nested functions are non-standard extension. I also have doubts about static this variable.
The non-standard nested function printId is used incorrectly. In GCC documentation Nested functions one can read:
If you try to call the nested function through its address after the containing function exits, all hell breaks loose.
The nested functions are called via trampolines, the small pieces of executable code located on stack. This code is invalidated when the parent function exits.
Though as the functions does not refer to any local variables the code will likely work. The compiler will likely avoid trampolines but rather create a kind-of "anonymous" static function.
The idiomatic solution should take a pointer to "Object" as an argument rather than use a static variable.
typedef struct Object {
int id;
void (*printId)(struct Object*);
} Object;
void printId(Object *this){
printf("%d\n", this->id);
};
...
object->printId(object);
There are advantages for using a struct to organize data for bulk processing. However, the only advantage of using the function pointer rather than calling the function directly would be:
To allow the function pointer to point to different functions having the same type for different instances of the object.
To hide the "member" function definition from the linker. For example, the function printId could be declared as static within the module containing the definition for "constructor" new_Object.

How to create unique static variables in function pointers?

I'm trying to create a unique static variable for each function pointer and I need to use a function pointer because I plan on using them inside of a struct.
I tried creating a function pointer to a function with a static variable but it's the same variable in both of them.
#include <stdio.h>
void foo()
{
static int test = 10;
test++;
printf("%d\n", test);
}
void (*bar)() = foo;
int main()
{
foo();
bar();
return 0;
}
I expected this to give me 11 and 11 but I get 11 and 12 so it must increment the same variable twice.
This is not something a function pointer can do.
Instead of function pointers, you probably want some kind of object-orientation so you can have several objects each with its own private test field, but sharing the same code.
For this, you need to go to C++ instead of plain C.
(If for some reason this is not available to you and you have to do your stuff in C, there's no real way around giving the function an extra context pointer as a parameter. Or, if you need only finitely many instances of the function, write it several times. They can share a helper function that does the real stuff, but each instance needs to declare their own memory for the helper function to operate on).

Why doesn't this assignment work outside of a function?

Here's an example of what I have going on. This first piece of code will not work.
typedef struct {
char *desc;
unsigned quantity;
} item;
item *inventory[INVENTORY_SIZE];
item thing = { "This is a thing.", 2 };
inventory[0] = &thing; // Fail.
int main(void){
// Code goes here.
}
The following code will work, however.
typedef struct {
char *desc;
unsigned quantity;
} item;
item *inventory[INVENTORY_SIZE];
item thing = { "This is a thing.", 2 };
int main(void){
inventory[0] = &thing; // Works.
}
I know I can't call functions outside of a function but that I can assign globals outside of a function. This looks like an assignment. So then why doesn't it work?
EDIT: As soon as I clicked 'post', I think I realised the answer. You can assign values in a declaration outside of a function, but only if it's a declaration. That's the answer, isn't it?
When we write :
data_type variableName = someValue;
It means we are first declaring variableName to be a variable, and of the type data_type. Subsequently, an assignment of a value is being done, immediately afterwards and since this is the first value assigned to variableName, it's also initialising it to someValue.
Which is allowed. This is a special type of function, a system function, known as initialisation.
But writing
variableName = someValue;
means we are attempting to assign someValue to variableName outside the scope of any function, and outside the scope of an initialisation.
This is not possible outside a function.
Code only executes from within called functions, with the exception of initialisation, which occurs during an initial assignment.
This should work, if it what you're trying to accomplish:
item thing = { "This is a thing.", 2 };
item *inventory[INVENTORY_SIZE] = {&thing};
These are definitions (since they are at top level scope), so the compiler will go ahead and allocate storage for them in this translation unit.
item thing = { "This is a thing.", 2 };
is not an assignment despite what it may look like. It's actually an initialisation (part of a declaration) which is perfectly valid outside of a function.
On the other hand,
inventory[0] = &thing;
is an assignment which has to be inside a function of some description.
Bottom line, you should not apply initialisation rules to assignments.
Youre guess is right: the second example is initialisation, rather than execution of the statement. It's legal because global variables are created before the execution of the program (i.e., initial call to main function). Think of it like that: the command flow starts in the main function and it goes into all function that is called from it as they are called in the program's code. So at any moment the program is within some function, and any commands (besides initializations which are done beforehand) that do not lie within some function are automatically dead code --- the program has no means to reach them.
First of all,
item thing = { "This is a thing.", 2 }
is an initialization, which is a special case, not an assignment. This sets the initial value of a variable. Initialization is bonded with declaration, so it can reside in a file scope.
The assignment expression can only reside inside a function. To put it in simple words, an assignment needs to be executed at run-time, so if it is not inside a function scope, there is no way to know when to execute it.

C multiple pthread call to function in another file and store a value to the variable in there as global

I have a main main.c that create multiple thread with same function.
I'm using pj_thread_t from PJSUA API as the thread.
then I separate the pjsua api function in different file let's say pjsua.c. So I can call it from the thread in main.
in the pjsua.c,
there is a global variable, let's say int index_room_number
there is a a function to call room using pjsip call function, let's say void * make_call(int* index_of_room)
in the pjsua api, there is a callback function to detect the current call state, so there is a function static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
in main.h,
I store every room number in a
#define MAX 260
struct Room {
int number;
char* guest;
time_t wake;
unsigned int in_queue : 1;
unsigned int is_called : 1;
unsigned int call_count : 2;
unsigned int status;
};
extern struct Room room[MAX];
for every room need to be called in the main thread, I create a new thread, and than call the make_call function passing the index_of_room. In that function make_call, I access the room[index_of_room].number and call the sip extensions.
The on_call_state function will be automatically print the status_code if the call is confirmed, or rejected.
The problem is, I need somehow to update the room[index_of_room].status from on_call_state, but the index_of_room value is exist only in the function make_call. So I store the index_of_room in the global variable of index_room_number in order to expose the value to the on_call_state.
Then another problem appear, that is, the index_room_number being overwritten by every thread that call the function make_call because the variable is shared between all thread. So I need the global variable that could appear in all of the function in pjsua.c, but will contain different value for every thread that call that function.
How to achieve something like that. I'm still new to C Programming, so I couldn't figure out the correct way to do it.
If in OOP, maybe that file can be analogous as a class.
One solution is to pass the variable around everywhere it is needed.
To make the solution extendable (adding more variables with minimal work), put the variable in a struct:
typedef struct myContext {
int intVar;
char *stringVar;
} MyContext;
Then you add a MyContext* parameter to all functions that need access to the threads global variables.
Example of usage:
int foo(MyContext* context, int param1, int param2) {
if (context->intVar == 0) {
// Do something special
}
}
EDIT:
Unfortunately, this technique doesn't work with 3rd party callback architectures since you cannot change the function signatures.
In callback architectures you are usually supplied with some kind of identifier in the callback. If you associate the identifier with the struct and store the structs in a collection (array, linked list, map, whatever is best suited for the task) you can then use the identifier to retrieve the right struct. Note that manipulation of the collecton must be protected from concurrent usage, for example by a mutex.
In your case, in your make_call function you would associate the call id with a room number.
In your callback you can look up the association and get the right struct.
When the call ends, or is dropped, you remove the association.

Structure return and comparison with another function inside main

Can you please help me understand something regarding structures?
I have created two structures with elements, here I have one in every case. I have a function called "function" that calculates the elements of the first structure struct_a and returns struct_a.
When I compile the code below, I receive two warnings:
warning: return makes integer from pointer without a cast
warning: function returns address of local variable
What do I do wrong?
Now I want to call this structure inside main and put the elements of this to another structure.
First, is it correct the way I call it within the main? Or I should give some arguments?
The goal is that: Inside main, I want to put the values of the "struct_a" to the structure "car_a". Any advice please?
struct characteristics
{
int element ;
};
struct car type = {int alpha};
int function(){
struct characteristics struct_a[10];
sruct_a[2].element_a = var;
return struct_a;
}
int main(){
function();
struct characteristics struct_a[10];
car.alpha = struct_a[2].element_a;
}
You're getting warnings because you're defining struct_a to be an array of characteristics structures, meaning struct_a is the pointer (address) to the first structure in that array, while the function function() is expecting to return an int value.
You need to match the return type of function() with the variable type you are returning.
There are some other issues w/ the code, and I'm not entirely sure why struct_a is defined as an array in the first place, but maybe this will get you started in the right direction.

Resources