C : Calling a pointer

Programming, for all ages and all languages.
Post Reply
User avatar
IanSeyler
Member
Member
Posts: 326
Joined: Mon Jul 28, 2008 9:46 am
Location: Ontario, Canada
Contact:

C : Calling a pointer

Post 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
BareMetal OS - http://www.returninfinity.com/
Mono-tasking 64-bit OS for x86-64 based computers, written entirely in Assembly
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: C : Calling a pointer

Post 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.
Every good solution is obvious once you've found it.
User avatar
qw
Member
Member
Posts: 792
Joined: Mon Jan 26, 2009 2:48 am

Re: C : Calling a pointer

Post by qw »

Prototypes of functions returning pointers to functions are even trickier...

Not to scare you off. Typedef is your friend.
User avatar
IanSeyler
Member
Member
Posts: 326
Joined: Mon Jul 28, 2008 9:46 am
Location: Ontario, Canada
Contact:

Re: C : Calling a pointer

Post 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
BareMetal OS - http://www.returninfinity.com/
Mono-tasking 64-bit OS for x86-64 based computers, written entirely in Assembly
User avatar
qw
Member
Member
Posts: 792
Joined: Mon Jan 26, 2009 2:48 am

Re: C : Calling a pointer

Post 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
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: C : Calling a pointer

Post by pcmattman »

Cast to a function pointer. Problem solved. There is no need for assembly stubs or anything of the sort.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: C : Calling a pointer

Post by Solar »

Why cast anything? Why disguise a function pointer as something different? We don't pass around float values as long int either...
Every good solution is obvious once you've found it.
Post Reply