I'm talking about:
struct {
struct spinlock lock;
struct proc proc[NPROC];
} ptable;
which resides in proc.c file.
Can someone please explain where it is initialized?
Because, in proc.c I've never seen something (process) being added to it.
To be more precise, let's say I'm looking at the scheduler code:
void
scheduler(void)
{
struct proc *p;
for(;;){
// Enable interrupts on this processor.
sti();
// Loop over process table looking for process to run.
acquire(&ptable.lock);
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
if(p−>state != RUNNABLE)
continue;
// Switch to chosen process. It is the process’s job
// to release ptable.lock and then reacquire it
// before jumping back to us.
proc = p;
switchuvm(p);
p−>state = RUNNING;
swtch(&cpu−>scheduler, proc−>context);
switchkvm();
// Process is done running for now.
// It should have changed its p−>state before coming back.
proc = 0;
}
release(&ptable.lock);
}
}
In:
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
you can see that we are looping thorough each process in ptable. My question is, how did they get there?
Thanks!
It is initialised.
struct {
struct spinlock lock;
struct proc proc[NPROC];
} ptable;
the above code defines a struct (with no name) and initialises ptable as one struct of this type.
maybe you are confusing with this syntax:
struct ptable {
struct spinlock lock;
struct proc proc[NPROC];
};
here we are only defining a struct name ptable and there are no initialisations.
You won't find the initialization in xv6's code. Here's why.
C initializes proc's int and enum variables to 0. When ptable is implemented, struct proc proc[NPROC]; creates an array of 64 processes whose fields are initialized to 0 by the language. 0 happens to be the value of the UNUSED enumeration.
allocproc loops through ptable.proc looking for state=UNUSED, then initializes the first one it finds to all the needed values. So there's no need to explicitly initialize the structures in the array.
struct {
struct spinlock lock;
struct proc proc[NPROC];
}ptable;
It's allocated on the stack and initialized automatically. The trick here is that it's written in the GCC way, also called anonymous struct.
The struct ptable being a global variable was loaded into memory as a part of the bootmain() call during the booting of xv6 kernel. Since it is global, the default values are initialized.
Now coming to how they are actually used for storing processes and when the entries are modified.
The first process is created by userinit() which chooses an unused entry and uses it for setting up its own PCB.
After the hand crafted initproc is made by the kernel, the first call to scheduler happens which is what you are referring to here.
Since the scheduler will select a RUNNABLE process and the only one we have right now is the initproc itself, it is the one that starts running.
It makes a call to fork() for spawning a shell which calls allocproc() on each call to get another unused entry from ptable and allocate it to the process.
This is how the ptable is populated during fork and helps xv6 do a book keeping of the active processes.
Related
I have a problem with this program in C. In a nutshell I have to send the data created by a sensor, through an aggregator. The aggregator, through a writer thread, read the value generated by the sensor to three different queues through three reader threads (thread_lettore) only that when I create the threads, all three connect to the last queue created. I would like have each thread with its own queue. Passing the message queue id of the sensor is easy because is only one message queue but how can I pass a different message queue id to each thread?
I found the error in this for cycle but I can't resolve it. It generates the correct queues but when I pass the arguments to the pthread_create, it pass only the last queue created.
MonitorLS * m = (MonitorLS*) malloc(sizeof(MonitorLS));
for (int i=0; i<3; i++){
m->id_coda_c = id_code_collettori[i];
pthread_create(&threads[i], &attr, thread_lettore, (void*)m);
}
This is the structure in the header file:
typedef struct {
int variabile;
pthread_mutex_t mutex;
pthread_cond_t cv_lett;
pthread_cond_t cv_scritt;
int num_scrittori;
int num_lettori;
int id_coda_s;
int id_coda_c;
} MonitorLS;
This is how I create three different message queues in the main file:
char chiave = 'a';
int id_code_collettori[3];
for (int i=0; i<3; i++){
key_t key_c = ftok (".", chiave);
id_code_collettori[i] = msgget(key_c, IPC_CREAT|0644);
chiave = chiave + 1;
}
This is a homework exercise that my university professor assigned to me. Sorry for my bad english.
The problem is you only allocate one MonitorLS struct.
You put the first queue ID in the struct. You start the first thread. You put the second queue ID in the struct. You start the second thread. You put the third queue ID in the struct. You start the third thread.
... a few microseconds later, the first thread starts up and looks at the struct and gets the queue ID (which is the third one because that's what you put there).
... a few microseconds later, the second thread starts up and looks at the struct and gets the queue ID (which is the third one because that's what you put there).
... a few microseconds later, the third thread starts up and looks at the struct and gets the queue ID (which is the third one because that's what you put there).
So, you need to use three different variables to store the three different queue IDs, instead of using one variable three times. You could allocate three different MonitorLS structs, one per thread. In fact, that is basically your only option. I see that MonitorLS has other stuff in it, though, so you might want to make another struct (let's call it ThreadInfo), that has a pointer to your MonitorLS struct (same pointer in every ThreadInfo) and a queue ID (different in every ThreadInfo).
How a mutex variable inside a structure or linke list actually takes effect. Does it locks the complete structure ? Actually when it's declared inside a structure then how it works ? what are inside details of it's working ?
Here is an sample code from oracle site :-
typedef struct node1 {
int value;
struct node1 *link;
pthread_mutex_t lock;
} node1_t;
node1_t ListHead;
node1_t *delete(int value)
{
node1_t *prev, *current;
prev = &ListHead;
pthread_mutex_lock(&prev->lock);
while ((current = prev->link) != NULL) {
pthread_mutex_lock(¤t->lock);
if (current->value == value) {
prev->link = current->link;
pthread_mutex_unlock(¤t->lock);
pthread_mutex_unlock(&prev->lock);
current->link = NULL;
return(current);
}
pthread_mutex_unlock(&prev->lock);
prev = current;
}
pthread_mutex_unlock(&prev->lock);
return(NULL);
}
so in above code in line 10 - thread_mutex_lock(&prev->lock); how it serves it's purpose.
Is it some standard rule to follow ?
Thanks
Mutexes don't lock things. You lock mutexes.
When you run pthread_mutex_lock(&prev->lock);, it locks the mutex, and no other thread can lock the same mutex until you unlock it. If another thread tries to, it will wait until you unlock it.
The mutex does not know about the structure. That is up to your program.
I'm not a 100% sure what you're asking. A mutex can be locked, and a struct can include such mutex, but I don't think that a mutex really "locks" the whole structure.
Let's simplify your question by just looking at the following struct.
typedef struct node1 {
int value;
struct node1 *next;
pthread_mutex_t lock;
} node1_t;
According to the manual page of pthreads, calling pthread_mutex_lock(lock) tries to lock the mutex, after it is locked others cannot lock it until it is released.
In other words, after you lock the mutex, other codes will fail to lock it (before you release it), which is acting like "locking" the whole data structure. Every part of your code that accesses the structure first checks the mutex, so it acts like that we've locked the whole structure.
For more details, I advise you to read the following manual pages:
https://man7.org/linux/man-pages//man3/pthread_mutex_lock.3p.html
I have a data structure which I personally implemented that now needs to be used across multiple threads.
typedef struct
{
void** array_of_elements;
size_t size;
} myStruct;
For simplicity, let's say my data structure has these functions:
// Gets a data element from the structure.
void* get(myStruct *x);
// Prints out all the data elements.
void print(myStruct *x);
// Adds an element into the structure.
void add(myStruct *x, void *to_be_added);
It's not a problem whatsoever to call get while another thread is calling print since they are both accessors. However, get and print cannot work while add is currently being called. Vice versa, add cannot work if get and print are currently in-progress.
So I changed myStruct to look like the following:
typedef struct
{
void** array_of_elements;
size_t size;
// True when a mutator is editing this struct.
bool mutating;
// The number of threads currently accessing this struct.
int accessors;
} myStruct;
Now my functions look like the following:
void* get(myStruct *x)
{
// Wait for mutating to end.
while (x->mutating);
// Indicate that another accessor is now using this struct.
x->accessors++;
// get algorithm goes here
// Declare we are finished reading.
x->accessors--;
return ...
}
// Same as above...
void print(myStruct *x)
...
void add(myStruct *x)
{
// Wait for any accessors or mutators to finish.
while (x->mutating || x->accessors > 0);
x->mutating = true;
// add algorithm here
x->mutating = false;
}
BUT, I think there are a lot of problems with this approach and I can't find a way to solve them:
One of my classmates told me using while loops like this slows the thread down immensely.
It has no sense of a queue. The first method that begins waiting for the myStruct to finish being used isn't necessarily the one that goes next.
Even IF I had a queue data structure for which thread goes next, that data structure would also need to be synchronized, which in itself is an infinite loop of needing a synchronized data structure to synchronize itself.
I think it's possible that in the same nano second one thread changes the accessors counter from 0 to 1 (meaning they want to start reading), it's possible for a mutator thread to see it's value is 0 and start mutating. Then, both a mutator thread and an accessor thread would be going at the same time.
I'm pretty sure this logic can cause grid-lock (threads waiting on each other infinitely).
I don't know how to make certain threads sleep and wake up right when they need to for this task, besides having it stuck in a while loop.
You have the right idea, just the wrong approach. I'm not sure what OS you're programming on, but you want to look at the concepts of mutex or semaphore to do what you want to do.
On Linux/Unix that is POSIX compliant, you can look at pthreads:
http://www.cs.wm.edu/wmpthreads.html
On Windows, you can look at Critical Sections for something close to a mutex concept:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682530(v=vs.85).aspx
Or WaitForMultipleObjects for something close to a semaphore:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms687025(v=vs.85).aspx
And, yes, using while loops are a bad idea. In this case, you are using what is known as a busy loop. More reading on it here:
What is a busy loop?
Using mutex or semaphore, no while loop is required. Good luck!
I am trying to implement kernel level threads in xv6.
My main problem at the moment is to understand how the CPU gets its information about the current process and how to modify it to point to the current thread instead.
I know it is somehow linked to this line:
extern struct proc *proc asm("%gs:4");
in proc.h, but I do not fully understand how and why it works.
I found out %gs points to to the line struct cpu *cpu; in the struct cpu (defined at proc.h), and right below that line (+ 4 bytes after the cpu pointer)
the current process of the cpu is stored:
struct proc *proc; // The currently-running process.
so in order to add thread support one should either alter this line to point to the new thread struct instead of process struct or alternatively, add the thread below the "proc" line and perform the following changes:
add in proc.h the following decleration: extern struct thread *thread asm("%gs:8");
change in vm.c, in fucntion "seginit(void)" the line
c->gdt[SEG_KCPU] = SEG(STA_W, &c->cpu, 8, 0); to c->gdt[SEG_KCPU] = SEG(STA_W, &c->cpu, 12, 0); in order to allocate space for the extra thread pointer.
I have a Tcl main program and I want to create a C thread from it.
I then would need to share information between the two threads: C thread's process frequently updated inputs/outputs.
I see two possible solutions to my problem: (1) port Tcl's Thread Shared Variable to C, but I didn't see any information about it in the TCL-C API. (2) Create Tcl-C linked Variables and use it as arguments during the C thread creation.
The latter idea doesn't seem to work. Here is the C code:
#include <tcl.h>
/*
startRoutine
*/
static void startRoutine (ClientData clientData) {
int *Var;
Var= (int *) clientData;
int locA=0;
int j;
int k;
while (1) {
if (locA=!*Var) {
// Modify Tcl-C shared variable
locA=2 * *Var;
*Var=locA;
for (j=0; j<100; j++){}
} else {
for (k=0; k<100; k++){}
}
}
}
static int
createThreadC_Cmd(
ClientData cdata,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
// Contains the ID of the newly created thread
Tcl_ThreadId id;
// Thread argument
ClientData limitData;
// Transfering global var argument to the created thread
limitData=cdata;
// Thread creation
id=0;
Tcl_CreateThread(&id, startRoutine, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);
// Wait thread process, before returning to TCL prog
int i;
int aa;
for (i=0 ; i<10000000 ; i++){
aa=i;
}
// Return thread ID to tcl prog to allow mutex use
Tcl_SetObjResult(interp, Tcl_NewIntObj((int) id));
return TCL_OK;
}
int DLLEXPORT
Behavcextension_Init(Tcl_Interp *interp)
{
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
// Create global Var
int *sharedPtr;
int linkedVar=0;
sharedPtr=&linkedVar;
Tcl_LinkVar(interp, "linkedVar", (char *) sharedPtr, TCL_LINK_INT);
Tcl_CreateObjCommand(interp,
"createThreadC", createThreadC_Cmd, sharedPtr, NULL);
return TCL_OK;
}
Here is the Tcl code:
# linkedVar initial value in Tcl, will be overwritten by C Tcl_LinkVar() function
set linkedVar 98
puts "linkedVar: $linkedVar"
# Thread creation
#------------------
load [file join [pwd] libBehavCextension[info sharedlibextension]]
set threadId [createThreadC]
puts "Created thread $threadId, waiting"
# When Tcl_LinkVar() is called, initiate linkedVar at 2
puts "linkedVar: $linkedVar"
# Function inside thread should modify linkedVar into linkedVar*2
set linkedVar 98
after 5000
puts "linkedVar: $linkedVar"
The terminal output is here:
Main thread ID: tid0xb779b6c0
linkedVar: 98
Created thread -1227252928, waiting
linkedVar: 2
linkedVar: 98
The last result should be 2*98=196. LinkVar creation between Tcl and C is Ok (we get 2 after link creation), but passing LinkVar to the Thread is KO.
Any solution or explanations about why it doesn't work/what to do to solve it are welcome!
The problem remains the same as in the other question. You're allocating the storage for the variable on the C side on the C stack in a function that terminates shortly afterwards. It's Undefined Behavior to refer to that variable (which is linkedVar in Behavcextension_Init) after the termination of the function (Behavcextension_Init). What actually happens is that the actual storage is used for some other function call (doing who knows what) and so the value contained is arbitrary, and changing it can lead to “exciting” behavior.
You're looking to have a variable that exists after Behavcextension_Init finishes, so it must not be allocated in the stack of that function. The simplest method is this:
int DLLEXPORT
Behavcextension_Init(Tcl_Interp *interp)
{
int *sharedPtr;
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
sharedPtr = (int *) Tcl_Alloc(sizeof(int)); // Allocate
*sharedPtr = 0; // Initialize
Tcl_LinkVar(interp, "linkedVar", (char *) sharedPtr, TCL_LINK_INT);
Tcl_CreateObjCommand(interp,
"createThreadC", createThreadC_Cmd, sharedPtr, NULL);
return TCL_OK;
}
Caveats
This leaks memory, as there is no matching Tcl_Free for that Tcl_Alloc. For memory allocated once per process, that's not much of a problem. After all, it's only a few bytes and the OS will reclaim it at exit.
This is unsafe when reading the variable from a different thread than the one where it was written; there's simply no guarantee that it will work. It will probably work as it is just an integer, but you're depending on the hardware to be cooperative. The right thing to do is to allocate a structure containing both the variable and a suitable mutex, and protect the accesses to the variable (whether reads or writes) with the mutex. That in turn requires that you do not use Tcl_LinkVar — it knows nothing about mutex-protected memory — but Tcl_LinkVar is just a wrapper round Tcl_TraceVar that provides a callback that does the coupling between Tcl's variable (see Tcl_GetVar and Tcl_SetVar) and the C variable; writing your own that knows how to do mutex-protection handling as well is not hard. (If you're interested, get the source to Tcl_LinkVar and adapt it yourself; it doesn't use any private API calls.)