Page 1 of 1

C : Calling a pointer

Posted: Mon May 10, 2010 10:50 am
by IanSeyler
Hello,

I am currently working on the C library for my OS and I'm a bit stumped on one part.

Here is the C code. The b_smp_enqueue function works fine (It add the jobs to the queue and the available processors in the system start to execute them). This issue is the b_smp_dequeue function. While the other processors are running the jobs the calling program will just sit there spinning until all the work is done. b_smp_dequeue returns an unsigned long which is a pointer to a job.. but how can I get C to execute it? GCC returns "called object 'local' is not a function".. obviously :) Can I use an actual pointer?

Code: Select all

int main()
{
	unsigned long var1=0, var2=0, local=0;

	b_smp_enqueue(&loop_a);
	b_smp_enqueue(&loop_b);
	b_smp_enqueue(&loop_a);
	b_smp_enqueue(&loop_b);
	b_smp_enqueue(&loop_a);
	b_smp_enqueue(&loop_b);
	b_smp_enqueue(&loop_a);
	b_smp_enqueue(&loop_b);

	while (b_smp_queuelen() != 0)
	{
		local = b_smp_dequeue();
		local();
	}
	
	b_smp_wait();
	b_print_string("end\n");

	return 0;
}
Here is the ASM code that works as it is intended. The BSP executes jobs while the AP's are still processing:

Code: Select all

start:					; Start of program label

	mov rax, ap_print_id		; Our code to run on all CPUs
	xor rbx, rbx			; Clear RBX as there is no argument
	mov rcx, 64			; Number of instances to spawn

spawn:
	call os_smp_enqueue
	sub rcx, 1
	cmp rcx, 0
	jne spawn

bsp:
	call os_smp_dequeue		; Try to dequeue a workload
	jc emptyqueue			; If carry is set then the queue is empty
	call rax			; Otherwise run the workload
	call os_smp_queuelen		; Check the length of the queue
	cmp rax, 0
	jne bsp				; If it is not empty try to do another workload

emptyqueue:
	call os_smp_wait		; Wait for all other processors to finish
	call os_print_newline

ret					; Return to OS
If you need anything else please let me know.

Thanks,
-Ian

Re: C : Calling a pointer

Posted: Mon May 10, 2010 10:58 am
by Solar
Consider () an operator that can only be called on objects of type "pointer to function".

A function is by no means limited to returning only integer values. Floats, structs, pointers are possible too.

So, by all means, yes, you can use an actual pointer. Look up "function pointers" in your C manual of choice, they are a bit tricky syntactically.

Re: C : Calling a pointer

Posted: Mon May 10, 2010 11:28 am
by qw
Prototypes of functions returning pointers to functions are even trickier...

Not to scare you off. Typedef is your friend.

Re: C : Calling a pointer

Posted: Mon May 10, 2010 11:41 am
by IanSeyler
I took the quick and easy way: A new OS function.

Code: Select all

int main()
{
	unsigned long var1=0, var2=0, local=0;

	b_smp_enqueue(&loop_a);
	b_smp_enqueue(&loop_b);
	b_smp_enqueue(&loop_a);
	b_smp_enqueue(&loop_b);
	b_smp_enqueue(&loop_a);
	b_smp_enqueue(&loop_b);
	b_smp_enqueue(&loop_a);
	b_smp_enqueue(&loop_b);

	while (b_smp_queuelen() != 0)
	{
		local = b_smp_dequeue();
		if (local != 0)
			b_smp_run(local);
	}
	
	b_smp_wait();
	b_print_string("end\n");

	return 0;
}
b_smp_run is this:

Code: Select all

void b_smp_run(unsigned long ptr)
{
	asm volatile ("call 0x001001B0" : : "a"(ptr));
}
which is just "call rax; ret".

For some reason I couldn't do a "call %rax". The C program runs as expected now (Loop B takes twice as long to execute).

On a single core: A B A B A B A B
On a quad core: A A B B A A B B
On a 8 core: A A A A B B B B

It seems that all this Assembly coding has destroyed my memory of C. How can a typedef help?

-Ian

Re: C : Calling a pointer

Posted: Mon May 10, 2010 12:01 pm
by qw
What a dirty hack! Did you look up "function pointers" already?

The "local" variable should be a pointer to a function, and the "b_smp_dequeue" function should return a pointer to a function.

A typedef is not necessary, but the syntax of function pointers is kind of funny, and a typedef will drastically improve the readability of your code.

Good luck!

Roel

Re: C : Calling a pointer

Posted: Mon May 10, 2010 6:18 pm
by pcmattman
Cast to a function pointer. Problem solved. There is no need for assembly stubs or anything of the sort.

Re: C : Calling a pointer

Posted: Mon May 10, 2010 10:20 pm
by Solar
Why cast anything? Why disguise a function pointer as something different? We don't pass around float values as long int either...