0

I am working on the Nachos Operating System as part of my coursework. While modifying the codebase of the OS, I encountered the following comment for a member function that allows you to run a function inside a newly forked thread (in this OS, processes are called threads - don't ask me why - refer to the official documentation). What I am most interested in is the docstring above the function. I am particularly interested in the section NOTE of the comment. I am not entirely sure what is going on here. How can a struct be passed to the Fork function, and how should we write func if it's supposed to use multiple arguments through a struct? Can someone explain this?

//----------------------------------------------------------------------
// Thread::Fork
//  Invoke (*func)(arg), allowing caller and callee to execute 
//  concurrently.
//
//  NOTE: although our definition allows only a single integer argument
//  to be passed to the procedure, it is possible to pass multiple
//  arguments by making them fields of a structure, and passing a pointer
//  to the structure as "arg".
//
//  Implemented as the following steps:
//      1. Allocate a stack
//      2. Initialize the stack so that a call to SWITCH will
//      cause it to run the procedure
//      3. Put the thread on the ready queue
//  
//  "func" is the procedure to run concurrently.
//  "arg" is a single argument to be passed to the procedure.
//----------------------------------------------------------------------

typedef void (*VoidFunctionPtr)(int arg); 

void 
Thread::Fork(VoidFunctionPtr func, int arg)
{
    // run the function 'func' in side the forked thread using the argument
    // 'arg' as its input - look at VoidFunctionPtr type declaration above
}

I have one question that is related to my question on StackOverflow. I shall link it here. But, I am not completely sure if I understand it. Thanks in advance!

PS: Complete source code is linked here: code, thread.h, thread.cc

Edit: I understand that using the standard library thread and other standard library implementations is very safe and helpful, but as part of the coursework, I am not allowed to do this. In any case, I want to understand what the authors of this codebase are trying to say.

braceletboy
  • 98
  • 2
  • 7
  • 4
    They are assuming `sizeof (void *)` == `sizeof (int)`, which, depending on the machine architecture, is very much not guaranteed. – Paul Sanders Oct 03 '22 at 05:09
  • They’re assuming a pointer is convertible to a number and back, and that number fits in the definition of `int`. To my knowledge first one isn’t approved of by any standard and second one definitely isn’t going to work unless compilation environment is very specifically tailored to make it work. – Sami Kuhmonen Oct 03 '22 at 05:12
  • 1
    @SamiKuhmonen: The C Standard is clearly intended to recognize a category of implementations that can support a signed and/or unsigned integer type that supports round-tripping of points. The Standard guarantees that round-tripping a pointer via integer type will yield a pointer that compares equal to the original, but unfortunately fails to specify that the pointer may be used in any other fashion. I think it is clearly intended that round-tripped pointers be used as the original would have been, but the Standard fails to actually say that. – supercat Oct 03 '22 at 05:17
  • I would not recommend doing things like this it breaks typesafety. Have a look as std::async/std::thread and lambdas that's a much better way of passing functions and data to threads then this "C" style approach – Pepijn Kramer Oct 03 '22 at 05:18
  • But yes it is "possible" but it also relies on programmers to know and do the right thing to make it work at runtime. So it is likely to cause bugs. – Pepijn Kramer Oct 03 '22 at 05:23
  • @EricPostpischil: The Standard recognizes a category of implementations for which such behavior is guaranteed, specifically those which define `intptr_t` or `uintptr_t`. Implementations are not required to define those types, fbut if those types are defined, they must be integer types that behave as described. – supercat Oct 03 '22 at 05:56
  • As others have already explained they rely on converting a struct-pointer to int (and back). That is *not* guaranteed to work by the C standard but for your specific system it is probably guaranteed as a kind of add-on for the implementation. I just like to add that the C standard has `intptr_t` and `uintptr_t` that allows conversion of pointers to integer types and back. – Support Ukraine Oct 03 '22 at 05:57

1 Answers1

1

I want to understand what the authors of this codebase are trying to say.”

They are saying, if you want to pass more data than an int, put it into a structure of your own design, say some struct foo x, and pass (int) &x to Thread::Fork. Implicit in the fact they are instructing you to do this is that the Nachos operating system is supported only for platforms on which such conversions preserve the necessary address information of the pointer and support its conversion back to a pointer to the structure type.

For example, you could define struct foo this way:

struct foo
{
    int a;
    float b;
};

and define func this way:

void func(int arg)
{
    struct foo *p = (struct foo *) arg;
    printf("a is %d.\n", p->a);
    printf("b is %g.\n", p->b);
}
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312