Page 1 of 1

How to pass variable number of arguments to new processes?

Posted: Thu Mar 15, 2018 6:18 am
by rrd
I'm working on the process management features of a little embedded operating system and I'm stuck on the design of a function that can create processes that run a function with a variable number of parameters. Here's a simplified version of how I want my API to looks like:

Code: Select all

// create a new process
// * function is a pointer to the routine the process will run
// * nargs is the number of arguments the routine takes
void create(void* function, uint8_t nargs, ...);

void f1();
void f2(int i);
void f3(float f, int i, const char* str);

int main()
{
    create(f1, 0);
    create(f2, 1, 9);
    create(f3, 3, 3.14f, 9, "string");

    return 0;
}
And here is a pseudocode for the relevant part of the implementation of system call create:

Code: Select all

void create(void* function, uint8_t nargs, ...)
{
    process_stack = create_stack();
    first_arg = &nargs + 1;
    copy_args_list_to_process_stack(process_stack, first_arg);
}
Of course I'll need to know the calling convention in order to be able to copy from create's activation record to the new process stack, but that's not the problem. The problem is how many bytes do I need to copy. Even though I know how many arguments I need to copy, I don't know how much space each of those arguments occupy. So I don't know when to stop copying.

The Xinu Operating System does something very similar to what I want to do, but I tried hard to understand the code and didn't succeed. I'll transcript a very simplified version of the Xinu's create function here. Maybe someone understand and help me.

Code: Select all

pid32 create(void* procaddr, uint32 ssize, pri16 priority, char *name, int32 nargs, ...)
{
    int32        i;
    uint32      *a;     /* points to list of args   */
    uint32  *saddr;     /* stack address        */

    saddr = (uint32 *)getstk(ssize); // return a pointer to the new process's stack

    *saddr = STACKMAGIC; // STACKMAGIC is just a marker to detect stack overflow

    // this is the cryptic part
    /* push arguments */
    a = (uint32 *)(&nargs + 1);     /* start of args        */
    a += nargs -1;                  /* last argument        */
    for ( ; nargs > 4 ; nargs--)    /* machine dependent; copy args */
        *--saddr = *a--;            /* onto created process's stack */
    *--saddr = (long)procaddr;
    for(i = 11; i >= 4; i--)
        *--saddr = 0;
    for(i = 4; i > 0; i--) {
        if(i <= nargs)
            *--saddr = *a--;
        else
            *--saddr = 0;
    }

    *--saddr = (long)INITRET;	/* push on return address	*/
    
    // prptr->prstkptr is the stack pointer in the PCB
    prptr->prstkptr = (char *)saddr;
}
I got stuck on this line:

Code: Select all

a += nargs -1;
This should move the pointer a 4*(nargs - 1) ahead in memory, right? What if an argument's size is not 4 bytes? But that is just the first question. I also didn't understand the next lines of the code.

Re: How to pass variable number of arguments to new processe

Posted: Thu Mar 15, 2018 7:53 am
by thomasloven
A common way of passing arguments to new processes is in string form.
Otherwise you'll have to revise your API to somehow specify the type of each argument as well. A printf-like format string, perhaps?

Re: How to pass variable number of arguments to new processe

Posted: Thu Mar 15, 2018 9:24 am
by rrd
thomasloven wrote:Otherwise you'll have to revise your API to somehow specify the type of each argument as well.
How could I do that? Any ideas? I guess I could replace nargs with a parameter that receives the sum of the sizes of all the arguments together. But maybe that is a little hard to use and error prone.
thomasloven wrote:A printf-like format string, perhaps?
A little ugly, but it's an option. The drawback is its inability to handle user defined data types.

Re: How to pass variable number of arguments to new processe

Posted: Thu Mar 15, 2018 9:34 am
by iansjack
Concatenate the arguments into a string, whose address you pass on the stack. The startup code for the new process parses this string into the familiar argc, argv parameters,

Re: How to pass variable number of arguments to new processe

Posted: Thu Mar 15, 2018 3:26 pm
by thomasloven
rrd wrote:
How could I do that? Any ideas? [...]
thomasloven wrote:A printf-like format string, perhaps?
That... was my idea...

Re: How to pass variable number of arguments to new processe

Posted: Thu Mar 15, 2018 5:43 pm
by rrd
thomasloven wrote: That... was my idea...
OK! Thanks!

Re: How to pass variable number of arguments to new processe

Posted: Fri Mar 16, 2018 3:24 pm
by rrd
iansjack wrote:Concatenate the arguments into a string, whose address you pass on the stack. The startup code for the new process parses this string into the familiar argc, argv parameters,
I liked your idea. I'll try!