Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε

Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε

Δρ. Α. Κομνηνός/Δρ. Χ. Μακρής

Παρόμοιες παρουσιάσεις


Παρουσίαση με θέμα: "Δρ. Α. Κομνηνός/Δρ. Χ. Μακρής"— Μεταγράφημα παρουσίασης:

1 Δρ. Α. Κομνηνός/Δρ. Χ. Μακρής akomninos@ceid.upatras.gr

2 Σύνοψη 8ης ∆ιάλεξης Λειτουργικό Σύστημα Minix Ανάθεση Μνήμης
Ανταλλαγή ∆εδομένων Παράδειγμα: Αρχικοποίηση Σημάτων

3 ΔΜ με Μεταβαλλόμενα διαμερίσματα
Πόση μνήμη ανατίθεται σ' ένα process; Η δυσκολία έγκειται στο ότι συνήθως το μέγεθος ενός process μεταβάλλεται κατά την εκτέλεσή του. Ένα process έχει τρία τμήματα: - text: το object code («εκτελέσιμο»)- δεν μεταβάλλεται - data: τα δεδομένα -μεταβάλλεται [βλ. malloc()] - stack: το stack επίσης μεταβάλλεται Το data τμήμα μεγαλώνει προς το stack και αντίστροφα. Προσέξτε: αν δίναμε ακριβώς όσο χώρο χρειάζεται ένα process όταν εισέρχεται στη μνήμη, τότε θ' απαιτείται mem-to-mem αντιγραφή για να μεταφέρουμε ένα process που μεγαλώνει σε κάποιο άλλο διαμέρισμα.

4 Τμήματα ∆ιεργασιών Οι διεργασίες στο Minix 3 χωρίζονται σε τρία τμήματα text -- ο κώδικας (‘εκτελέσιμο’), δεν μεταβάλλεται data -- τα δεδομένα stack -- το stack εντολών Το τμήμα stack μεταβάλλεται προς το τμήμα data και αντίστροφα Το αρχικό μέγεθος ορίζεται από το αρχείο του εκτελέσιμου (στην επικεφαλίδα) Με την εντολή chmem μπορούμε να μεταβάλουμε το αρχικό μέγεθος Την μνήμη διαχειρίζεται ο PM. Κρατάει λίστα με «τρύπες». Εντοπίζει την 1η κατάλληλη και τη δίνει στην διεργασία. Οι διεργασίες δεν γίνονται ποτέ swapped και δεν παίρνουν περισσότερη ή λιγότερη μνήμη

5 Τμήματα ∆ιεργασιών – Θέματα Υλοποίησης (1)
Το μέγεθος του κάθε τμήματος μετριέται σε clicks Κάθε click είναι 1024 bytes Στο αρχείο /usr/src/include/minix/type.h ορίζεται η δομή mem_map που περιγράφει το κάθε τμήμα Εικονική θέση του τμήματος στην μνήμη (σε clicks) Πραγματική θέση του τμήματος στην μνήμη (σε clicks) Μέγεθος τμήματος(σε clicks) Η εικονική θέση και το μέγεθος μετριούνται σε unsigned int, η πραγματική θέση σε unsigned long struct mem_map { vir_clicks mem_vir; /* virtual address */ phys_clicks mem_phys; /* physical address */ vir_clicks mem_len; /* length */ };

6 Τμήματα ∆ιεργασιών – Θέματα Υλοποίησης (2)
Η πληροφορία για τη θέση του κάθε τμήματος και το μέγεθος διατηρείται στον πυρήνα και στον διαχειριστή διεργασιών Ορίζεται ως ένας πίνακας Η θέση 0 περιέχει το text (T) Η θέση 1 περιέχει το data (D) Η θέση 2 περιέχει το stack (S) Η σταθερά NR_LOCAL_SEGS είναι 3 και ορίζεται στο αρχείο /usr/src/include/minix/const.h (2 versions) /usr/src/commands/mdb/core.c /usr/src/kernel/proc.h /usr/src/servers/pm /usr/src/servers/vm/arch/i386 Επίσης ορίζει τις 3 βοηθητικές σταθερές (T, D, S) Πληροφορία στον Πυρήνα struct mem_map p_memmap[NR_LOCAL_SEGS]; Πληροφορία στον ∆ιαχειριστή ∆ιεργασιών struct mem_map mp_seg[NR_LOCAL_SEGS];

7 /* Type definitions. */ click=1024 bytes (protected mode) memory.h
typedef unsigned int vir_clicks; /* virtual addr/length in clicks */ typedef unsigned long phys_bytes; /* physical addr/length in bytes */ typedef unsigned int phys_clicks; /* physical addr/length in clicks */ typedef int endpoint_t; /* process identifier */ typedef int32_t cp_grant_id_t; /* A grant ID. */ typedef long unsigned int vir_bytes; /* virtual addresses/lengths in bytes */

8 Τμήματα ∆ιεργασιών – Μέγεθος Τμημάτων
Κατά την αρχικοποίηση της διεργασίας ορίζονται τα 3 τμήματα (μέγεθος, θέση) Μπορεί ένα τμήμα να χρειαστεί περισσότερο χώρο (αφορά το data, stack) Λογικό για το μεγαλύτερο μέρος των προγραμμάτων Αφήνουμε ένα ‘κενό’ μεταξύ data -- stack Μειώνουμε το κόστος ‘μεταφοράς’ των τμημάτων σε νέες θέσεις μνήμης με μεγαλύτερο ελεύθερο χώρο

9 Τμήματα ∆ιεργασιών – Παράδειγμα
Τα τρία τμήματα της διεργασίας: text -- μέγεθος 3K data -- μέγεθος 4K stack -- μέγεθος 2K Κενό μεταξύ data -- stack 1K Συνολικό μέγεθος 10K Περιεχόμενα πίνακα: Το text και data θεωρούνται ότι είναι σε κοινό τόπο (παλιές εκδόσεις). Στις νέες εκδόσεις I+D χωριστά. 0xΧΧ είναι το «click» στο οποίο θα πάμε αντί για πραγματική διεύθυνση.

10 Εκτέλεση Εντολών – ∆ημιουργία Νέων ∆ιεργασιών
Θέλουμε να εκτελέσουμε μια νέα εντολή Αρχικά χρησιμοποιούμε την κλήση του συστήματος fork Αντιγράφονται τα τμήματα μνήμης της A Αμέσως μετά χρησιμοποιούμε την κλήση του συστήματος exec Αντικαθιστώνται τα τμήματα μνήμης από αυτά της C Στο unix κάθε φορά που κάνουμε μια εντολή, το shell κάνει fork τον εαυτό του και μετά αντιγράφει τα δεδομένα της εντολής στο νέο address space.

11 Κοινά Τμήματα Μνήμης
#//usr/src/include/minix/type.h #//usr/src/include/minix/priv.h #/usr/src// kernel / arch / i386 / protect.c, prot_init (descriptor tables) #/usr/src/servers/vm/vproc.h Στα αλληλεπιδραστικά συστήματα μια διεργασία μπορεί να ‘τρέχει’ πολλές φορές . . . αντίγραφα του ίδιου κώδικα στην μνήμη π.χ. χρησιμοποιώντας την κλήση του συστήματος fork Στην ουσία το τμήμα text είναι κοινό για όλες τις διεργασίες Θέλουμε να εντοπίσουμε κατά πόσο μια διεργασία χρησιμοποιεί το ίδιο τμήμα text Ανατρέχουμε στο εκτελέσιμο της διεργασίας Αν δεν έχουν γίνει αλλαγές, πρόκειται για αντίγραφο /* File identification for sharing. */ ino_t mp_ino; // inode number of file dev_t mp_dev; // device number of file system time_t mp_ctime; // inode changed time

12 Κοινά Τμήματα Μνήμης – Παράδειγμα

13 MINIX memory management philosophy is simple: variable number of variable sized partitions with no swapping or paging . From the a.out file, the sizes of code, initialized data, uninitialized data, and initial stack are determined. Then a ``fudge factor'' called thegap is added to the total. A contiguous group of bytes of this size is allocated from the hole list. The process is never moved and never swapped. It is never given more or less memory. The gap lies between the stack and data, as shown in Figure Calls to malloc() in a C program result in brk() system calls which shrink or expand the gap. Pushing and popping the stack also shrink and grow the gap, but on the other end. In keeping with the MINIX philosophy, MM runs as a server process outside the kernel. System calls like fork() and exec() send messages to MM. MM uses the system task to inform the kernel about new and terminated processes and to access memory outside its address space. MM handles the system calls listed in Figure 4-34.

14 The Intel Pentium has an on-chip MMU that supports paged segments
The Intel Pentium has an on-chip MMU that supports paged segments. There are at most 16K segments, each up to 4G bytes in size. There are two 8K tables of segment descriptors, the per-process local descriptor table LDT and the fixed global descriptor table GDT. Six of these segment descriptors can be ``active'' at a time, being loaded into six segment descriptor registers. MINIX uses two of these registers: code CS and data DS. A segment descriptor contains the base address and size of the segment. All addresses generated by a process are an offset into the relevant segment, code or data. To convert the segment offset pair into a physical address, the offset is added to the base address of the segment, giving the linear address. If paging is disabled, i.e., the Pentium is being run as a pure segmented system, this so-called linear address is the physical address. This is the case in MINIX, since it does not page nor swap.

15 Each process has three MINIX segments: code also called text, data, and stack. But MINIX only uses two Intel segments: code and data. There are two MINIX memory models: common I and D space, and separate I and D space. In the first, all three MINIX segments are in one Intel segment and the code and data Intel segments are identical. In the second, the Intel code segment holds the MINIX code segment and the MINIX data and stack segments are in the Intel data segment. From now on, ``segment'' will refer to a MINIX segment. Separate I and D space allows different processes that are executing the same code, say several users logged in and editing files, to share the same code segment. Code segments are always read-only

16 It takes nine numbers (in clicks) to describe the memory map of a process, drawn here in ASCII art, three for each of the text, data, and stack segments. Each segment has a length, a physical address, and a virtual address relative to the beginning of the Intel segment it is in. See Figure In common I and D, all three MINIX segments are in one Intel segment. MINIX puts a zero in the text segment length field and puts the same physical address in the text and data physical address field. In separate I and D, the MINIX text segment has its own Intel segment while the MINIX data and stack segments share an Intel segment. In both models, the MINIX stack segment starts at a physical and virtual address above the gap (which is above the MINIX data segment) in the Intel data segment.

17 In both models, the gap lies between the data and stack segments
In both models, the gap lies between the data and stack segments. The stack grows down into the gap and the data grows up into the gap. If they collide, the process address space becomes corrupted and the process will crash or generate erroneous results. There is a CPU register, the stack pointer, that is decremented on stack pushes and incremented on pops. At every brk() system call, MINIX checks the stack pointer against the memory map of the stack and makes adjustments. If the stack and data segments have collided, brk() returns an error. But the damage may already have been done.

18 Unallocated memory is kept track of in a hole list
Unallocated memory is kept track of in a hole list. To allocate memory, this list is searched first fit. Common I and D needs one allocation. Separate I and D first looks for text it can share. If so, do one allocation for data/stack segment. If not, do one allocation for both text segment plus data/stack segment. They need not be contiguous, but MINIX just searches once for one hole big enough to contain both. fork() System Call Figure 4-37 shows the steps. In separate I and D, text segment is shared with the parent, of course. Both the kernel (system task) and FS must be told about the new process (the child ). exit() and wait() A process terminates when it calls exit() or is killed by a signal. Its memory is released but it is a zombie until its parent does a wait()for it, at which time its process table slot is reclaimed. If a process terminates but its parent is not around, having earlier terminated, the process becomes an orphan and is inherited by the init process, which is in a wait() loop just for such orphans.

19 Check is made to see if there is enough memory without adding in what will be released (current memory occupied by the process). This is faster but may fail unnecessarily. The search of the hole list is made for one hole big enough to hold all of text, data, gap, and stack. If separate I and D, a copy of the text is search for in memory and used if present, and the hole searched for will contain only data, gap, and stack. If separate I and D and a copy of the text is not found, then one hole big enough to hold text contiguous with data-gap-stack is search for. This is faster but less than optimal. Two searches of the hole list could be done: one for text and another for data-gap-stack since they need not be contiguous.

20 Θέματα Σχεδιασμού / Αρχιτεκτονικής
Η διαχείριση της μνήμης στο Minix 3 είναι ιδιαίτερα απλή ∆εν υλοποιεί μηχανισμό σελιδοποίησης (paging) Υλοποιεί έναν απλό μηχανισμό swapping -- απενεργοποιημένο Συγκεκριμένοι λόγοι για αυτή την στρατηγική Απλούστευση συστήματος – μείωση κώδικα Απόφαση προηγούμενων εκδόσεων Ευκολία στην μεταφορά σε ενσωματωμένα συστήματα Αν θελήσουμε να υλοποιήσουμε έναν μηχανισμό σελιδοποίησης ή κάποιον σύνθετο μηχανισμό swapping Ο διαχωρισμός των λειτουργιών στον διαχειριστή διεργασιών και στον πυρήνα διευκολύνει σε μεγάλο βαθμό Ο πυρήνας ασχολείται με θέματα ανάθεσης μνήμης, δημιουργίας διεργασιών κλπ. σε χαμηλό επίπεδο Ο διαχειριστής διεργασιών ασχολείται με την υλοποίηση των μηχανισμών – δεν χρειάζεται να κάνουμε αλλαγές στον πυρήνα

21 ∆ιαχείριση Οπών Μνήμης
Στην θεωρία (Λ.Σ. Ι) μελετήσαμε 2 μηχανισμούς διατήρησης των οπών μνήμης – έστω η κατώθι κατάσταση της μνήμη (a) Χρήση bitmap (b) ή χρήση Linked List (c) Το Minix 3 χρησιμοποιεί μια λίστα οπών (Hole List) First fit, Next fit Best fit

22 Λίστα Οπών Μνήμης – Εσωτερικές ∆ομές
Στο αρχείο /usr/src/include/minix/type.h ορίζεται η δομή hole που περιγράφει την κάθε οπή Στο αρχείο /usr/src/servers/pm/alloc.c γίνεται η διαχείριση των οπών και υλοποιούνται οι μηχανισμοί διαχείρισης της μνήμης Εσωτερικά διατηρούνται ορισμένες μεταβλητές struct hole { struct hole *h_next; // pointer to next entry on t phys_clicks h_base; // where does the hole begin? phys_clicks h_len; // how big is the hole? }; #define NIL_HOLE (struct hole *) 0 PRIVATE struct hole *hole_head; // head of list PRIVATE struct hole hole[_NR_HOLES];

23 Μηχανισμοί ∆ιαχείριση Μνήμης
Το αρχείο /usr/src/servers/pm/alloc.c προσφέρει τις εξής συναρτήσεις: alloc_mem -- ∆έσμευση μνήμης συγκεκριμένου μεγέθους free_mem -- Αποδέσμευση μνήμης init_mem -- Αρχικοποίηση μνήμης κατά την εκκίνηση του διαχειριστή διεργασιών PUBLIC phys_clicks alloc_mem(phys_clicks clicks); PUBLIC void free_mem(base, clicks); phys_clicks base; // base address of block to free phys_clicks clicks; // number of clicks to free PUBLIC void mem_init(chunks, free); struct memory *chunks; // list of free memory chunks phys_clicks *free; // memory size summaries

24 Ανάθεση Μνήμης Η ανάθεση μνήμης είναι απλή – χρησιμοποιείται αποκλειστικά από τις κλήσεις του συστήματος fork και exec Η μνήμη που έχει ανατεθεί δεν μπορεί να μεγαλώσει/μικρύνει κατά την διάρκεια ζωής της διεργασίας Εάν πρόκειται για μια διεργασία που ‘μοιράζεται’ το τμήμα text με κάποια άλλη, τότε η ανάθεση μνήμης γίνεται μόνο για τα τμήματα data και stack Η συνάρτηση alloc_mem ανατρέχει την λίστα οπών έως ότου βρει την πρώτη εγγραφή που είναι αρκετά μεγάλη για να ‘χωρέσει’ το μέγεθος της μνήμης που θέλουμε να αναθέσουμε Αν δεν βρεθεί καμία εγγραφή (αρκετά μεγάλη) τότε Αν είναι ενεργοποιημένος ο μηχανισμός swapping -- προσπαθεί να κάνει swap out κάποια διεργασία και επαναλαμβάνει την αναζήτηση έως ότου βρεθεί μια αρκετά μεγάλη οπή Αν δεν μπορεί να βρεθεί (συνεχόμενος) ελεύθερος χώρος τότε επιστρέφει NO_MEM

25 Ανάθεση Μνήμης – Συνάρτηση alloc_mem (1)
PUBLIC phys_clicks alloc_mem(clicks) phys_clicks clicks; // amount of memory requested { register struct hole *hp, *prev_ptr; phys_clicks old_base; do { // try to allocate a block of memory // by searching the list of holes // if found, return a pointer to the block } while (swap_out()); /* try to swap some other process out * (if swaping is enabled) */ return(NO_MEM); }

26 Ανάθεση Μνήμης – Συνάρτηση alloc_mem (2)
prev_ptr = NIL_HOLE; hp = hole_head; while (hp != NIL_HOLE && hp->h_base<swap_base){ if (hp->h_len >= clicks) { /* We found a hole that is big enough. * Use it. * Return the start address of the * acquired block. */ return(old_base); } // Nothing found, continue to next hole prev_ptr = hp; hp = hp->h_next; }

27 Ανάθεση Μνήμης – Συνάρτηση alloc_mem (3)
// We found a hole that is big enough. Use it. old_base = hp->h_base; // remember where it started hp->h_base += clicks; // bite a piece off hp->h_len -= clicks; // ditto // Remember new high watermark of used memory if(hp->h_base > high_watermark) high_watermark = hp->h_base; // Delete the hole if used up completely if (hp->h_len == 0) del_slot(prev_ptr, hp); // Return the start address of the acquired block return(old_base);

28 Απελευθέρωση Μνήμης – Βοηθητική Συνάρτηση del_slot
PRIVATE void del_slot(prev_ptr, hp) register struct hole *prev_ptr; // hole entry ahead register struct hole *hp; // hole entry to be remove { /* Remove an entry from the hole list. * request to allocate memory removes a hole * in its entirety */ if (hp == hole_head) hole_head = hp->h_next; else prev_ptr->h_next = hp->h_next; hp->h_next = free_slots; hp->h_base = hp->h_len = 0; free_slots = hp; }

29 Απελευθέρωση Μνήμης
Η απελευθέρωση μνήμης είναι επίσης απλή. Χρησιμοποείται: από την κλήση του συστήματος exit ́Οταν είναι ενεργοποιημένος ο μηχανισμός swapping Προσπαθεί να εντοπίσει κάποια υπάρχουσα οπή που είναι ‘δίπλα’ στην θέση μνήμης που πρόκειται να απελευθερωθεί Συγχώνευση της θέσης μνήμης με την υπάρχουσα οπή Αλλιώς εισάγει μια νέα εγγραφή στην λίστα οπών με την θέση μνήμης που απελευθερώθηκε Ο πίνακας των οπών έχει συγκεκριμένο μέγεθος Το μέγεθος ορίζεται από την σταθερά _NR_HOLES ορίζεται σε (2*_NR_PROCS+4) -- αρχείο /usr/src/include/minix/sys_config.h Αν και είναι ικανοποιητικά μεγάλος (για τις απαιτήσεις του Minix 3) -- μπορεί να γεμίσει Σε αυτή την περίπτωση προκύπτει ένα kernel panic

30 Απελευθέρωση Μνήμης – Συνάρτηση free_mem (1)
PUBLIC void free_mem(base, clicks) phys_clicks base; // base address of block to free phys_clicks clicks; // number of clicks to free { register struct hole *hp, *new_ptr, *prev_ptr; if (clicks == 0) return; if ( (new_ptr = free_slots) == NIL_HOLE) panic(__FILE__,"hole table full", NO_NUM); new_ptr->h_base = base; new_ptr->h_len = clicks; free_slots = new_ptr->h_next; hp = hole_head;

31 Απελευθέρωση Μνήμης – Συνάρτηση free_mem (2)
/* If this block’s address is numerically * less than the lowest hole currently * available, or if no holes are currently * available, put this hole on the front * of the hole list. */ if (hp == NIL_HOLE || base <= hp->h_base) { // Block to be freed goes on front of the hole l new_ptr->h_next = hp; hole_head = new_ptr; merge(new_ptr); return; }

32 Απελευθέρωση Μνήμης – Συνάρτηση free_mem (3)
// Block to be returned does not go on // front of hole list prev_ptr = NIL_HOLE; while (hp != NIL_HOLE && base > hp->h_base) { prev_ptr = hp; hp = hp->h_next; } // We found where it goes. // Insert block after ’prev_ptr’ new_ptr->h_next = prev_ptr->h_next; prev_ptr->h_next = new_ptr; merge(prev_ptr);

33 Απελευθέρωση Μνήμης – Βοηθητική Συνάρτηση merge (1)
PRIVATE void merge(hp) register struct hole *hp; /* hole to merge with { // Check for contiguous holes and merge any found register struct hole *next_ptr; // ’hp’ points to the last hole, merging impossibl if ( (next_ptr = hp->h_next) == NIL_HOLE) return; if (hp->h_base+hp->h_len==next_ptr->h_base) { /* first one gets second one’s mem */ hp->h_len += next_ptr->h_len; del_slot(hp, next_ptr); } else { hp = next_ptr; }

34 Απελευθέρωση Μνήμης – Βοηθητική Συνάρτηση merge (2)
/* If ’hp’ now points to the last hole, * return; otherwise, try to absorb its * successor into it. */ if ( (next_ptr = hp->h_next) == NIL_HOLE) return; if (hp->h_base+hp->h_len==next_ptr->h_base) { hp->h_len += next_ptr->h_len; del_slot(hp, next_ptr); } }

35 Εικονική μνήμη Να υλοποιήσετε τον quick fit σαν ενα απο ΄πάνω μηχανισμό ο οποίος χωρίζει την μνήμη σε καταλόγους συγκεκριμένων ορίων μεγεθών και επιταχύνει την αντίστοιχη προσπέλαση. Ο PM χωρίζεται σε δύο κύρια μέρη Διαχείριση διεργασιών Διαχείριση μνήμης Η διαχείριση μνήμης γίνεται από ξεχωριστό server (VM) VM Paged mode Κάθε διεργασία έχει το δικό της virtual address space το οποίο διαχειρίζεται ο VM Έξτρα επίπεδο διευθυνσιοδότησης (physical, virtual, linear) Virtual -> linear (segments), linear -> physical (page tables) Κρατά τα page tables, τα οποία το kernel δεν τα βλέπει Κατά το boot, όλες οι διεργασίες τρέχουν σε segments Το kerner/table.c λέει ποιές θα συνεχίσουν σε segments και ποιές δικαιούνται να μεταβούν σε paged Non-paged mode (segments only)

36 Επικοινωνία ∆ιεργασιών
Το Λ.Σ. προσφέρει πολλούς τρόπους για την επικοινωνία μεταξύ διεργασιών Μηνύματα Σήματα Sockets / Pipes ∆ιαμοιραζόμενη μνήμη (shared memory) Οι μηχανισμοί αυτοί είναι υψηλού επιπέδου Παρέχουν σύνθετη λειτουργικότητα Προϋποθέτουν συνθετων μηχανισμών Πως μπορούν 2 διεργασίες να επικοινωνήσουν χωρίς την χρήση αυτών των μηχανισμών; ... θέλουμε ταχύτητα ... θέλουμε καλύτερο έλεγχο ... δεν μπορούμε να χρησιμοποιήσουμε αυτούς τους μηχανισμούς

37 Επικοινωνία ∆ιεργασιών – Απ ́ ευθείας Αντιγραφή Μνήμης
Ο πιό βασικός τρόπος είναι μέσω απ ́ ευθείας πρόσβαση στη μνήμη Οι μεταβλητές διατηρούνται στο data τμήμα μιας διεργασίας Αρκεί να ‘διαβάσουμε’ τη θέση μνήμης που βρίσκεται μια μεταβλητη ... ́Ομως είναι αυτος ο τρόπος ασφαλής; Οι διεργασίες χειρίζονται τα τμήματα μνήμης τους μεσω των εικονικών διευθύνσεων πως μπορούν να εντοπίσουν την θέση μνήμης σε μια άλλη διεργασία ;

38 Αντιγραφή Μνήμης Ο πυρήνας παρέχει μηχανισμούς (κλήσεις πυρήνα) για την αντιγραφή μνήμης Ασφάλεια : Αρχιτεκτονική Μικρο-πυρήνα – μόνο οι διαχειριστές / οδηγοί μπορούν να καλέσουν αυτούς τους μηχανισμούς Εικονικές ∆ιευθύνσεις: Ο πυρήνας γνωρίζει τις πραγματικές διευθύνσεις που έχουν τα τμήματα των διεργασιών ... Μετατρέπει τις εικονικές διευθύνσεις σε πραγματικές

39 Αντιγραφή Μνήμης – Κλήσεις Πυρήνα – SYS_VIRCOPY
Αντιγραφή από – διεργασία ‘πηγή’ (source) src_proc -- θέση διεργασίας στον πίνακα διεργασιών src_seg -- τμήμα μνήμης διεργασίας (text, data, stack) src_vir -- εικονική θέση μνήμης στη διεργασία Αντιγραφή πρός – διεργασία ‘προορισμός’ (destination) dst_proc -- θέση διεργασίας στον πίνακα διεργασιών dst_seg -- τμήμα μνήμης διεργασίας (text, data, stack) dst_vir -- εικονική θέση μνήμης στη διεργασία bytes -- Πλήθος bytes προς αντιγραφή _PROTOTYPE(int sys_vircopy, (int src_proc, int src_seg, vir_bytes src_vir, int dst_proc, int dst_seg, vir_bytes dst_vir, phys_bytes bytes));

40 Βοηθητική Συνάρτηση -- sys_vircopy (1)
/usr/src/lib/syslib/sys_vircopy.c PUBLIC int sys_vircopy(src_proc, src_seg, src_vir, dst_proc, dst_seg, dst_vir, bytes) int src_proc; /* source process */ int src_seg; /* source memory segment */ vir_bytes src_vir; /* source virtual address */ int dst_proc; /* destination process */ int dst_seg; /* destination memory segment */ vir_bytes dst_vir; /* destination virtual address */ phys_bytes bytes; /* how many bytes */ { ... }

41 Βοηθητική Συνάρτηση -- sys_vircopy (2)
/usr/src/lib/syslib/sys_vircopy.c { message copy_mess; if (bytes == 0L) return(OK); copy_mess.CP_SRC_ENDPT = src_proc; copy_mess.CP_SRC_SPACE = src_seg; copy_mess.CP_SRC_ADDR = (long) src_vir; copy_mess.CP_DST_ENDPT = dst_proc; copy_mess.CP_DST_SPACE = dst_seg; copy_mess.CP_DST_ADDR = (long) dst_vir; copy_mess.CP_NR_BYTES = (long) bytes; return(_taskcall(SYSTASK, SYS_VIRCOPY, &copy_mess)); }

42 Αντιγραφή Μνήμης – Κλήσεις Πυρήνα (1)
Το αρχείο /usr/src/include/minix/syslib.h ορίζει ‘παραλλαγές’ της sys_vircopy Λιγότερες παράμετροι ανάλογα την περίσταση sys_biosin sys_biosout sys_datacopy sys_textcopy sys_stackcopy sys_abscopy ́Ολες καταλήγουν στην do_copy /usr/src/kernel/system/do_copy.c

43 Αντιγραφή Μνήμης – Κλήσεις Πυρήνα (2)
Στο αρχείο /usr/src/kernel/system.h ορίζονται οι handlers για τις κλήσεις πυρήνα Στο αρχείο /usr/src/kernel/system.c γίνεται η αντιστοίχηση των handlers με τους αριθμούς των κλήσεων πυρήνα _PROTOTYPE( int do_copy, (message *m_ptr) ); #define do_vircopy do_copy #define do_physcopy do_copy map(SYS_VIRCOPY, do_vircopy); map(SYS_PHYSCOPY, do_physcopy);

44 /usr/src/kernel/system/do_copy.c
τύπος (m_type) -- SYS_VIRCOPY ή SYS_PHYSCOPY m5_c1 (CP_SRC_SPACE) -- source virtual segment m5_l1 (CP_SRC_ADDR) -- source offset within segment m5_i1 (CP_SRC_PROC_NR) -- source process number m5_c2 (CP_DST_SPACE) -- destination virtual segment m5_l2 (CP_DST_ADDR) -- destination offset within segment m5_i2 (CP_DST_PROC_NR) -- destination process number m5_l3 (CP_NR_BYTES) -- number of bytes to copy

45 Συνάρτηση -- do_copy (1)
Μετατρέπει τις παραμέτρους του μηνύματος σε 2 μεταβλητές τύπου vir_addr PUBLIC int do_copy(m_ptr) register message *m_ptr; { struct vir_addr vir_addr[2]; phys_bytes bytes; vir_addr[_SRC_].proc_nr_e = m_ptr->CP_SRC_ENDPT; vir_addr[_SRC_].segment = m_ptr->CP_SRC_SPACE; vir_addr[_SRC_].offset = (vir_bytes) m_ptr->CP_SRC_ADD vir_addr[_DST_].proc_nr_e = m_ptr->CP_DST_ENDPT; vir_addr[_DST_].segment = m_ptr->CP_DST_SPACE; vir_addr[_DST_].offset = (vir_bytes) m_ptr->CP_DST_ADD bytes = (phys_bytes) m_ptr->CP_NR_BYTES;

46 Συνάρτηση -- do_copy (2)
Ελέγχει τις διευθύνσεις – αν αναφέρονται σε ‘πραγματικές’ διεργασίες (/usr/src/kernel/arch/i386/memory.c Χρησιμοποιεί την συνάρτηση isokendpt_f ... ορίζεται στο αρχείο /usr/src/kernel/proc.c Στην ουσία μετατρέπει το αριθμό end-point σε αριθμό διεργασίας (θέση στον πίνακα διεργασιών) Αν η διεργασία δεν εντοπιστεί – ή δεν είναι ζωντανή – επιστρέφει έναν αρνητικό αριθμό Χρησιμοποιεί την συνάρτηση virtual_copy ορίζεται στο αρχείο /usr/src/kernel/system.c Μετατρέπει τις εικονικές διευθύνσεις σε πραγματικές με την χρήση της συνάρτησης umap_local Χρησιμοποιεί την συνάρτηση phys_copy για την τελική αντιγραφή – επίπεδο assembly (klib386.s)

47 Γενικά Θέματα Σημάτων
Ενας βασικός τρόπος επικοινωνίας των διεργασιών είναι και η χρήση σημάτων Μεταφέρουν πληροφορία σε διεργασίες που δεν περιμένουν κάποια είσοδο Χαρακτηρίζονται ως τα «interrupt λογισμικού» Το MINIX 3 ακολουθεί το πρότυπο POSIX Ο κώδικας που αναπτύσσεται σε άλλο λειτουργικό UNIX μπορεί να μεταφερθεί στο MINIX 3 με ‘σχετική’ ευκολία ́Οπως και με τα υπόλοιπα ζητήματα, η υλοποίηση των σημάτων είναι μινιμαλιστική

48 Βασική Λειτουργία Σημάτων
́Οταν μια διεργασία λάβει ένα σήμα, το σύστημα ορίζει κάποιες προκαθορισμένες αντιδράσεις Τερματισμός (kill τον παραλήπτη) Αγνόησέ το Μια διεργασία μπορεί να ζητήσει κάποια σήματα να αγνοηθούν Μια διεργασία μπορεί να αλλάξει την προκαθορισμένη αντίδραση για ένα σήμα ορίζοντας έναν signal handler Επομένως υπάρχουν τρεις βασικές φάσεις για την διαχείριση των σημάτων Προετοιμασία: Ρυθμίσεις σημάτων και αντιστοίχηση signal handler Απάντηση: Χρήση signal handler όταν ληφθεί ένα σήμα Επαναφορά: επιστροφή της διεργασίας στην ‘κανονική’ ροή εκτέλεσης Το Λ.Σ. αναλαμβάνει να εκτελέσει τον signal handler και να επαναφέρει την διεργασία στην προηγούμενη ροή εκτέλεσης Συνήθης αντίδραση (θάνατος)

49 Προετοιμασία Σημάτων
Για κάθε διεργασία αντιστοιχούν διάφορες μεταβλητές τύπου sigset_t (στον πίνακα των διεργασιών) Για τα σήματα που πρέπει να διαχειριστούμε Για τα σήματα που πρέπει να αγνοήσουμε Κ.α. Ορίζεται στο αρχείο /usr/src/include/signal.h (/sys/sigtypes.h) /usr/src/sys/sys/signal.h ως typedef unsigned long sigset_t; Χρησιμοποιείται ως bitmap όπου κάθε bit αντιστοιχεί σε ένα σήμα Έτσι γνωρίζουμε ποιά σήματα μπορεί να χειριστεί κάθε διεργασία

50 Προετοιμασία Σημάτων
Οι ρυθμίσεις για τη διαχείριση ενός τύπου σήματος γίνεται με μεταβλητές τύπου sigaction Υπάρχουν διάφορες κλήσεις του συστήματος για την ρύθμιση της αντίδρασης μιας διεργασίας σε εισερχόμενα σήματα sigaction -- ορισμός signal handler, επαναφορά προκαθορισμένης αντίδρασης, ‘απενεργοποίηση’ σήματος Ο signal handler ορίζεται ως (/usr/src/sys/sys/signal.h) typedef void _PROTOTYPE( (*__sighandler_t), (int) ); Για κάθε διεργασία, για κάθε σήμα, αντιστοιχεί μια μεταβλητή τύπου sigaction (στον πίνακα των διεργασιών) struct sigaction { /* SIG_DFL, SIG_IGN, or pointer to function */ __sighandler_t sa_handler; /* signals to be blocked during handler */ sigset_t sa_mask; /* special flags */ int sa_flags; };

51 Προετοιμασία Σημάτων – Παράδειγμα
testsignal.c void catch_int(int sig_num) { printf("Don’t do that..."); } int main() { struct sigaction sig; sigset_t sset; sigemptyset(&sset); sig.sa_flags = 0; sig.sa_handler = catch_int; sig.sa_mask = sset; sigaddset(&sig.sa_mask, SIGINT); sigaction(SIGINT, &sig, NULL);

52 Βοηθητική Συνάρτηση sigaction
Ορίζεται στο αρχείο /usr/src/lib/libc/sys-minix/sigaction.c PUBLIC int sigaction(sig, act, oact) int sig; _CONST struct sigaction *act; struct sigaction *oact; { message m; m.m1_i2 = sig; m.m1_p1 = (char *) act; m.m1_p2 = (char *) oact; m.m1_p3 = (char *) __sigreturn; return(_syscall(MM, SIGACTION, &m)); }

53 Κλήση Συστήματος SIGACTION (1)
PUBLIC int do_sigaction() { int r; struct sigaction svec; struct sigaction *svp; ... r = sys_datacopy(PM_PROC_NR, (vir_bytes) svp, who_e, (vir_bytes) m_in.sig_osa, (phys_bytes) sizeof(svec)); ... }

54 Κλήση Συστήματος SIGACTION (2)
... /* Read in the sigaction structure. */ r = sys_datacopy(who_e, (vir_bytes) m_in.sig_nsa, PM_PROC_NR, (vir_bytes) &svec, (phys_bytes) sizeof(svec)); ... }

55 Διαχείρηση Μνήμης (3.2.1) Δεν υπάρχουν πια τα Μinix segments (text/data/stack αφηρημένες οντότητες μνήμης τουπυρήνα) με αποτέλεσμα την απλοποίηση της χωροθέτησης μνήμης και στη συμβατότητα με non-Intel αρχιτεκτονικές. Υπάρχουν μόνο δύο τύποι διευθύνσεων: εικονικές και φυσικές ενώ οι διεργασίες αι ο πυρήνας έχουν τον ίδιο χώρο εικονικών διευθύνσεων. Διαφοροποιούνται στο ότι οι διεργασίες δεν χρησιμοποιούν 0xF  και άνω.

56 Λεπτομέρειες Υλοποίησης
Για να ενσωματώσει αποτελεσματικά λειτουργικότητα εικονικής μνήμης, ο Διαχειριστής Διεργασιών διασπάστηκε σε αποκλειστικό Διαχειριστή Διεργασιών (PM) και σε Διαχειριστή Μνήμης (VM). O VM υλοποιεί όλα τα τμήματα διαχείρησης μνήμης των fork, exec, exit καλούμενος συγχρονα με τον PM. Το επόμενο σχήμα επιδεικνύει τη σειρά των κλήσεων για το fork.

57 VM server O VM διαχειρίζεται τη μνήμη (καταγράφει δεσμευμένη και χρησιμοποιούμενη μνήμη, ανάθεση μνήμης σε διεργασίες, απελευθέρωση). Υπάρχει μία ξεκάθαρη διάσπαση ανάμεσα σε αρχιτεκτονικά ανεξάρτητα και εξαρτώμενα κομάτια. Για i386 και ARM, υπάρχουν intel page tables που βρίσκονται στο VM address space. VM απεικονίζει αυτά στον χώρο διεύθυνσης της, επεξεργαζόμενη το δικό της page table οπότε μπορούν να τα επεξεργαστούν άμεσα.

58 Regions O χώρος διευθύνσεων κάθε διεργασίας περιγράφεται στη struct vmproc δομή δεδομένων και οργανώνεται ως μία απλή συνδεδεμένη λίστα από περιοχές (regions). Μία περιοχή αναπαριστά ένα εύρος διευθύνσεων εικονικής μνήμης και περιγράφεται στη struct vir region δεδομένων και έχει μία αρχική διεύθυνση (εικονική διεύθυνση), ένα μήκος και επισημαίνεται με συγκεκριμένα flags. Κάθε region έχει ένα συγκεκριμένο τύπο και μερικούς παραμέτρους. Ο τυπος της καθορίζει τις ιδιότητες και συμπεριφορά (“memory types”) δε χρειάζεται real memory που να πραγματοποιείται σε αυτή. Μερικές φορές το μέγεθος μπορεί να γίνει resized (brk call). Κάθε memory type περιγράφεται από τη struct mem_type στο memtype.h. Αυτές υλοποιούνται σε mem_.*c source files και δηλώνονται στο glo.h. Συνεπώς έχουμε generic υλοποιήσεις.

59 Physical Regions Η virtual region είναι η βασική μονάδα απεικονίσεων συνεπώς τα flags περιέχουν πληροφορία σχετική με τις απεικονίσεις μνήμης. Κάθε virtual region περιέχει μία ακολουθία (fixed size array of pointers) από άλλες ομάδές αναπαράστασης μνήμης που ονομάζονται physical region, στη struct phys region δομή δεδομένων. Για τη βελτίωση της ταχύτητας πρόσβασης για τέτοιες regions, το MINIX χρησιμοποιεί AVL δέντρα για την αποθήκευση σε αυτά. Kάθε entry αναπαριστά ένα page-sized memory block, εάν non-NULL το block πραγματοποιείται και δείχνει σε μία phys-region που περιγράφει ένα physical block μνήμης

60 Claudiu-Dan Gheorghe and Andrei Faur, Memory Mapped Files on MINIX

61 To κλειδί για τις physical regions είναι η μετατόπιση από την αρχή της virtual memory region, αλλά υπάρχει επίσης επιπρόσθετη πληροφορία που βοηθά το σύστημα να μταφράσει τις εικονικες διευθύνσεις σε φυσικές διευθύνσεις. Συνεπώς κάθε physical region συνδέεται με την parent virtual region μέσω μίας πολλά προς ένα σχέσης και συνδέεται με μία άλλη δομή δεδομένων που ονομάζεται physical block χρησιμοποιώντας μία ένα προς ένα σχέση. Οι physical regions είναι επίσης τμήμα μία άλης δομής δεδομένων, που είναι μία συνδεδεμένη λίστα από physical regions που αναφέρονται στο ίδιο physical block.

62 Το physical block περιγράφεται στη struct phys region δομή δεδομένων
Το physical block περιγράφεται στη struct phys region δομή δεδομένων. Περιέει ένα μήκος που είναι ο αριθμός των bytes στη συνεχή περιοχη μνήμης που αναπαριστά, ένα reference count που είναι ο αριθμός των physical regions που αναφερονται στη physical region, το πρώτο στοιχείο της συνδεδεμένης λίστας από physical regions που περιγράφηκε προηγουμένως και το πιο σημαντικό μία physical memory address. Με τον τρόπο αυτό έχοντας αναπαραστήσει τη μνήμη σαν μία φυσική περιοχή και όχι σαν ένα physical block επιτρέπει στο σύστημα να μοιράζεται εύκολα σελίδες μνήμης ανάμεσα από διάφορες physical regions, virtual regions και address spaces που ανήκουν σε διαφορετικές διεργασίες.

63 Όλη η πληροφορία για αυτές τις δομές δεδομένων απο θηκεύεται στο VM server, αλλά η δομή δεδομένων που ρησιμοποιείται για τη μετάφραση εικονικών διευθύνσεων σε φυσικές διευθύνσεις από το MMU των επεξεργαστών είναι ο πίνακας σελίδων. Συνεπώς κάθε αλλαγή στο χώρο διευθύνσεων γίνεται ορατή μόνο μετά τον συγχρονισμό των αλλαγών με το περιεχόμενο των πινάκων σελίδων. MINIX έχει ένα ιεραρχικό πίνακα σελίδων με ένα κατάλογο σελίδων 1024 εισόδων (10 bits) και υλοποιείται μόνο στην i386 αρχιτεκτονική.

64 Οι ελεύθερες περιοχές φυσικής μνήμης αποθηκεύονται στη VM χρησιμοποιώντας ένα συνολικό AVL tree που ερωτάται κάθε φορά που είναι απαραίτητο ένα σύνολο από σελίδες μνήμης. Όλες οι αναθέσεις μνήμης αναστέλλονται όσο περισσότερο με τον ίδιο τρόπο που αναστέλλονται στο Linux kernel, και είναι αντικείμενο διαχείρησης των διαφόρων memory pagefaults. Από την προοπτική του VM server τα pagefaults είναι κανονικά μηνύματα που λαμβάνονται από την διεργασία πυρήνα.

65 Το VM δεν εξυπηρετεί μόνο διεργασίες χρηστών αλλά και διεργασίες πυρήνα. Η προσέγγιση είναι παρόμοια σαν το Linux και ένα slab allocator χρησιμοποιείται. Το slab είναι η δομή δεδομένων που χρησιμοποιείται για την διαχείρηση αναθέσεων μνήμης μικρών αντικειμένων σε μία struct vir region. Αυτό που είναι μη αποτελεσματικό στις αναθέσεις μνήμης δεν είναι απλώς το τέλειωμα μίας οπής στην ελεύθερη μνήμη αλλά η διαδικασία αρχικοποίησης. Αυτός είναι και ο σκόπος του slab: η διατήρησης μίας συλλογής από αντικείμενα συγκεκριμένου μεγέθους που μπορούν να χρησιμοποιηθούν χωρίς αρχικοποίηση.

66 Το πρωταρχικό κλειδί για το slab allocator είναι το μέγεθος του αντικειμένου. Χρησιμοποιεί ένα πεπερασμένο σύνολο από slabs για ένα εύρος από ένα ελάχιστο (τώρα στο MINIX έχουμε ένα ελάχιστο 8 bytes) και ένα μέγιστο μέγεθος (SLABSIZE macro, που ορίζεται ως 60 bytes) σε ένα πίνακα που δεικτοδοτείται με μετατόπιση το μέγεθος του αντικειμένου. Κάθε slot του slab table περιγράφεται στο struct slabheader και περιέχει δεικτες στις κεφαλές τριών λιστών: LIST FREE η λίστα των free slabs, LIST USED η λίστα των partial free slabs, και LIST FULL η λίστα των slabs γεμισμένη με αντικειμένα. Ένα slab σαρώνει μία απλή σελίδα μνήμης, και αποτελείται από ένα header, που περιγράφεται στη struct sdh δομή δεφομένων, and το υπόλοιπο κομμάτι της σελίδας χρησιμοποιέται για την αποθήκευση των αντικειμένων. Οι λίστες υλοποιούνται σαν διπλοσυνδεδεμένες λίστες που επιτρεπουν σε ενα slab να μετατοπίζεται από μία λίστα στην άλλη σε σταθερό χρόνο.

67 Claudiu-Dan Gheorghe and Andrei Faur, Memory Mapped Files on MINIX

68 Claudiu-Dan Gheorghe and Andrei Faur, Memory Mapped Files on MINIX

69 Cache Oι in-VM disk block cache δομές δεδομένων και κώδικες για τη διαχείρηση τους περιέχονται στη cache.c. Κάθε cache block είναι page-sized και ταυτοποιείται από ένα (device, device offset) ζέυγος. Επιπλέον έχει (inode, inode offset) σαν εξτρα πληροφορία αλλά αυτό δεν απαιτείται να είναι μοναδικό στο VM, ούτε απαιτείται να είναι παρών. Ο inode αριθμός μπορεί να είναι VMC_NO_INODE, εννοώντας ότι το disk block δεν είναι μέρος του inode data η το inode number δεν είναι γνωστό (λ.χ. επειδή τέλειωσε στη cache μέσα από ένα block device και όχι μέσα από ένα αρχείο). Τα block περιεχόμενα είναι ένας 'Physical block' δείκτης, και στη cache μετράει σαν 'reference' στο refcount. Blocks δεικτοδοτούνται από hash πίνακες: ένα το (device, device offset) ζεύγος, και δύο, το (inode, inode offset) ζευγάρι. Ένα block iείναι παρών στο 2nd hashtable εάν είναι ένα inode at all (inode != VMC_NO_INODE). Επιπλέν cache blocks είναι σε μί α LRU chain που θα χρησιμοποιηθεί για εξαγωγη σε out-of-memory συνθήκες.

70 Τυπικά δομή κλήσης Οι κλήσεις στο VM λαμβάνονται από τρεις βασικές κυριες πηγής: χρήστες, PM και τον πυρήνα. Σε κάθε περίπτωση μία τυπική ροή ελέγχου είναι: Λήψη μηνυμάτων στο main.c Call-specific work in call-specific file, e.g. mmap.c, cache.c Διαχείρηση δομών δεδομένων υψηλού επιπέδου καλώντας συναρτήσεις στο region.c Ενημέρωση process pagetable με κλήση συναρτήσεων στο pagetable.c Ένα παράδειγμα είναι mmap, που αναθέτει μνήμη:

71 Βιβλιογραφία Βιβλίο ‘‘Operating Systems Design and Implementation, Third Edition’’ (Andrew S. Tanenbaum) Κεφάλαιο 4: Memory Management Παράγραφος 4.2 Swapping Παράγραφος Memory Layout Παράγραφος Process Manager Data Structures and Algorithms Παράγραφος The FORK, EXIT, and WAIT System Calls Παράγραφος The Header Files and Data Structures Παράγραφος The Main Program Παράγραφος Memory Management Utilities Βιβλίο ‘Σύγχρονα Λειτουργικά Συστήματα’ (A.Tanenbaum) Κεφάλαιο 4: ∆ιαχείριση Μνήμης Παράγραφος 4.8 Segmentation


Κατέβασμα ppt "Δρ. Α. Κομνηνός/Δρ. Χ. Μακρής"

Παρόμοιες παρουσιάσεις


Διαφημίσεις Google