Newsgroup: it.comp.os.dibattiti
Titolo: Stack e thread, varie ed eventuali

Nel progetto a cui sto lavorando per l'esame di sistemi operativi, mi è
capitato di non saper dare risposta ad alcuni problemi NON BANALI... quale
occasione migliore per rivitalizzare un newsgroup ormai in letargo.
Precisamente, la discussione a proposito di dove viene allocato lo stack mi
ha ricordato alcuni interrogativi difficili da risolvere.
Architettura di riferimento: il solito processore MIPS R2000... ogni
processo vede uno spazio di indirizzamento virtuale così segmentato:
0x0000.0000-0x003F.FFFF -> riservato
0x0040.0000-0x0FFF.FFFF -> .text e .rdata (codice e header)
0x1000.0000 e superiori -> .data e .bss (dati statici)
dalla fine dei dati statici in su -> heap (cresce verso indirizzi superiori)
===
fino a 0x7FFF.EFFF -> stack (cresce verso il basso)
0x7FFF.F000-0x7FFF.FFFF -> non utilizzato
0x8000.0000-0xFFFF.FFFF -> riservato
Un sistema operativo che debba caricare in memoria un programma registrato
su disco o nastro, non ha alcun problema ad allocare le pagine di memoria
necessarie al codice e ai dati statici (ne conosce le dimensioni); anche per
lo stack non c'è alcun problema, visto che l'allocazione/deallocazione è
richiesta esplicitamente dal processo al sistema operativo. Con lo stack è
un altro paio di maniche. Evidentemente il sistema operativo, caricando in
memoria il programma, allocherà almeno un frame di memoria allo stack, ma
chi mi garantisce che poi il processo stesso non avrà bisogno di più di 4kb
nello stack? Forse il sistema operativo, al primo accesso in memoria non
valido, dovrà verificare se il processo intendeva accedere allo stack (ad
esempio leggendo il valore dello stack pointer) e allocare nuovi frame di
conseguenza? Ammesso che questa sia una tecnica accettabile, come mi
comporto per rilevare e deallocare le pagine di stack non più necessarie?
Cosa fa un sistema operativo serio in questi casi?
Secondo quesito: due o più thread di uno stesso processo condividono lo
stesso spazio di indirizzamento. Non dovrebbero però condividere lo stack.
Allocando semplicemente gli stack dei vari thread in posizioni diverse non
risolvo il problema, perché comunque gli stack ampliandosi potrebbero finire
per sovrapporsi, oppure un thread bacato potrebbe scrivere sullo stack di un
thread fratello. L'unica soluzione è dunque servirsi di tabelle delle pagine
almeno parzialmente diverse per i vari thread? Ma in questo modo lo
scheduling risulta molto appesantito...
Ignoranti saluti.
--
//   Xelloss da Bologna  || in real life: Wilmer Ricciotti   \\
|  
wirix...@libero.it
 (elimina il demone per rispondermi)  |
|    ICQ: 3233084        IRC: Xelloss@AzzurraNet, @ChatNow    |
| Hardware Information & Technology: 
http://hit.edengames.net
 |
\_______Like the Phoenix I rise from the ashes of life________/

 scheduling risulta molto appesantito...
una volta no letto da qualche parte che i thread in linux vengono
implementati con la _fork che accetta una serie di parametri per decidere
come forkare. Prova a guardare la documentazione di _fork



Piu` che fork(2), clone(2) (versione piu` generale di fork(2), buona per 
processi e thread).
Nella manpage relativa c'e` questa interessante informazione al riguardo
...
The child_stack argument specifies  the  location  of  the
stack  used  by  the  child  process.  Since the child and
calling process may share memory, it is not  possible  for
the  child  process  to  execute  in the same stack as the
calling process.  The calling process must  therefore  set
up  memory space for the child stack and pass a pointer to
this space to clone.  Stacks grow downwards on all proces­
sors  that  run  Linux  (except  the HP PA processors), so
child_stack usually points to the topmost address  of  the
memory space set up for the child stack.
...
-- 
   |   \    \  | ___|_  |_  | ianezz a casa sua... :-)
   |  _ \  | \ | _|    /   /  Visita il LinuxTrent a
  _|_/  _\_|  _|____|___|___| 
http://www.linuxtrent.it

 memory space set up for the child stack.
E' interessante ma mi sembra un po' troppo di basso livello... veramente si
lascia al processo l'incombenza di gestirsi lo stack? brrr...
Saluti.
--
\/   | |         Wilmer Ricciotti - ICQ UIN: 3233084
/\ e | | o s s   
wi...@libero.it
HiT - EdenGames: 
http://hit.edengames.net
sito  personale: 
http://www.cs.unibo.it/~ricciott/
 (non attivo)

 lascia al processo l'incombenza di gestirsi lo stack? brrr...
E' così praticamente per ogni SO. Tipicamente i thread non hanno stack 
"autoestendibile".
-- 
"Everything is vague to a degree you do not realize till you have tried
  to make it precise"
                                       Bertrand Russell
                                       The Philosophy of Logical Atomism

 lo stack non c'č alcun problema, visto che l'allocazione/deallocazione č
  ^^^^^^^^
Spero che fosse comprensibile dal contesto, ad ogni modo qui intendevo "lo
heap" e non "lo stack".


 questo modo lo scheduling risulta molto appesantito...
questa e' una bella domanda...uhmmm...
secondo me varia dal modello di threding utilizzato, ma mi potrei sbagliare
benissimo...
cmq, per senza farci troppe paranoie nel tuo caso, dico che nello stesso
processo ci sono + stack in diverse posizioni per ogni thread generato, cmq
prendi tutto con le pinze perche':
1) e' tardi e sono stanco
2) tutto e' relativo =)
-- 
Paolo
On air: In Flames - World of promises

 fratello. 
è un rischio del multithreading che si deve accettare
-- 
  < 
http://www.reactos.com/
 >  Open source clone of Windows NT. Current
      Don't stand, REACT!      version 0.1.1. C, C++ and ASM developers
                               and beta testers are welcome!

 è un rischio del multithreading che si deve accettare
Brrrrrr... infatti avevo la vaga idea che il rischio non potesse essere
evitato. La scienza dei sistemi operativi non è una scienza esatta, a quanto
pare...
Grazie mille Juliet, precisa come al solito, ma dove le impari tutte queste
cose? :P
Invidiosi saluti.


 è un rischio del multithreading che si deve accettare
Brrrrrr... infatti avevo la vaga idea che il rischio non potesse essere
evitato. La scienza dei sistemi operativi non è una scienza esatta, a quanto
pare...
Grazie mille Juliet, precisa come al solito, ma dove le impari tutte queste
cose? I miei amici non riescono a credere che tu sia una donna, se ti capita
vieni a fare un giro su #caristudenti (
irc.freenode.net
) nel tardo
pomeriggio :PPP


 "autoestendibile".
Il che significa che ogni programmatore dovrebbe valutare le dimensioni
massime dello stack, ma ciò è in generale impossibile. Allo stato attuale,
ci sono compilatori o librerie che valutano i limiti dello stack e
prevengono bachi fastidiosi?


 prevengono bachi fastidiosi?
Certo, praticamente tutti i compilatori per i suddetti OS prevedono la 
possibilità di fare controlli sullo stack ed estenderlo quando 
necessario. Ovviamente ciò comporta codice più lento.


 autoestendibile per definizione.
Ho detto "in generale". Ovviamente nel caso banale conosciamo le dimensioni
massime raggiunte dallo stack, ma non appena si fa un certo uso di chiamate
di funzione ricorsive NO.
La tua obiezione sui sistemi operativi senza indirizzamento virtuale
comunque mi sembra inutile, č ovvio che se un programma ha accesso alla
rappresentazione fisica della memoria puň rilevare autonomamente gli
overflow dello stack, ovvero puň rilevarli il processore stesso lanciando
l'opportuna eccezione. Sotto DOS capitava non di rado che un programma
terminasse per "overflow dello stack".


 l'opportuna eccezione.
Stai facendo un po' di confusione... Force si sono alcuni processori che 
rilevano lo stack overflow, altri non possono farlo, e comunque la cosa 
ha nulla a che vedere con l'assenza di memoria virtuale.
Io sto parlando di sistemi operativi che non fanno uso della MMU e 
pertanto non possono proteggere pagine dello stack per catturare 
overflow ed estendere lo stack di conseguenza.


 overflow ed estendere lo stack di conseguenza.
Posso però intercettare l'overflow dello stack pointer, o in alternativa
l'overflow di qualsiasi registro.
Naturalmente tutto ciò che ho detto si applica con indirizzamento fisico e
sistema monoprogrammato... non per niente di solito il multitasking è
associato all'indirizzamento virtuale...


 ...
Come ti ho detto, non tutti i processori hanno questa funzionalità. I 
68k non l'hanno, ad esempio.


 68k non l'hanno, ad esempio.
In effetti, dalla FAQ di uCLinux:
http://www.uclinux.org/pub/uClinux/FAQ.shtml
   ...
   uClinux does not have autogrow stack and no brk(). You need to use
   mmap() to allocate memory (which most modern code already does).
   There is a compile time option to set the stack size of a program.
   ...
Inoltre ricordo che su AmigaOS la dimensione massima dello stack di un 
processo era fissa (mi pare 4KB o 8KB per default) e determinata 
all'avvio del processo.
(ok, *in teoria* si potrebbe comunque scrivere il codice in modo tale da 
effettuare un controllo tutte le volte che si piazza qualcosa sullo 
stack, ma ovviamente e` a carico dei singoli "processi" farlo visto che 
non c'e` il supporto in hardware della cosa, e oltretutto rallenterebbe 
di molto le cose).


 di molto le cose).
Come detto, tutti i compilatori per AmigaOS hanno la possibilità di 
generare codice del genere.


 68k non l'hanno, ad esempio.
No non lo hanno. Anche gli overflow generici sono segnalati unicamente dal
rispettivo flag, per cui sta al programma rilevare la fine dello stack - se
intende farlo.


 rallenterebbe di molto le cose).
Il costo dipende da una serie di fattori. Con funzioni piccole puň
facilmente essere non trascurabile, ma abilitando ad esempio
ottimizzazioni aggressive per sostituire chiamate di funzione, dove
possibile, con codice in linea, il costo viene ridotto due volte: la
prima semplicemente perché vengono chiamate meno funzioni; la seconda
perché i controlli che continuano ad essere eseguiti vengono
ammortizzati ora su funzioni in media piů lunghe.
Anche in questo caso un buon compilatore puň fare tranquillamente la
differenza. Con SAS/C č possibile abilitare l'estensione dello stack
solo per specifiche funzioni, definendole con l'attributo __stackext
(l'opzione stackext, in pratica, equivale a definire tutte le funzioni
__stackext). In tal modo il controllo puň essere effettuato solo nelle
sezioni di codice potenzialmente pericolose, dove lo stack potrebbe
essere usato in misura piů pesante o dove potrebbe esservi ricorsione.
-- 
 Perfection is attained not when there is no longer anything to add,
 but when there is no longer anything to take away (A. de Saint-Exupery)
 Rudi Chiarito                                            
ru...@amiga.com

 tutte queste cose? :P
sito in firma! (e un rompiballe che da due giorni mi importuna via ICQ, 
raccontandomi mille interessanti fatti sull'allocazione dello stack dei 
thread in Windows)


 non valida e ingestibile. Ok.
Tipicamente si controlla se l'indirizzo che ha causato il fault si trova
tra  la base  dello stack  e lo  stack pointer:  in questo  caso vengono
allocate le  pagine necessarie. Su x86  la cosa e` molto  semplice visto
che e` praticamente  gestito tutto in hardware (la pagina  di guarda non
c'e`,  alla fine  dello stack  non c'e`  mappato nulla  ed un  accesso a
questa zona causa un fault.).
Btw, questo link potrebbe interessarti:
http://www.csn.ul.ie/~mel/projects/vm/
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
"Chi parla in tono cortese, ma continua a prepararsi, potra` andare avanti;
 chi parla in tono bellicoso e avanza rapidamente dovra` ritirarsi" 
Sun Tzu -- L'arte della guerra