Lines Matching +full:un +full:-

1 .. include:: ../disclaimer-ita.rst
5 :Original: :ref:`Documentation/kernel-hacking/locking.rst <kernel_hacking_lock>`
23 Dato il largo utilizzo del multi-threading e della prelazione nel kernel
26 multi-processore.
33 In un normale programma, potete incrementare un contatore nel seguente modo:
44 +------------------------------------+------------------------------------+
48 +------------------------------------+------------------------------------+
50 +------------------------------------+------------------------------------+
52 +------------------------------------+------------------------------------+
54 +------------------------------------+------------------------------------+
56 +------------------------------------+------------------------------------+
58 +------------------------------------+------------------------------------+
64 +------------------------------------+------------------------------------+
68 +------------------------------------+------------------------------------+
70 +------------------------------------+------------------------------------+
72 +------------------------------------+------------------------------------+
74 +------------------------------------+------------------------------------+
76 +------------------------------------+------------------------------------+
78 +------------------------------------+------------------------------------+
82 ---------------------------------
84 Questa sovrapposizione, ovvero quando un risultato dipende dal tempo che
88 macchine multi-processore, le sezioni critiche sono diventate uno dei
92 interrompendo un processo nella sua sezione critica otterremo comunque
97 simultanei, ed utilizzare i *lock* per accertarsi che solo un'istanza
105 Se dovessi darvi un suggerimento sulla sincronizzazione: **mantenetela
111 ------------------------------------------------------------
114 spinlock (``include/asm/spinlock.h``), un semplice *lock* che può essere
115 trattenuto solo da un processo: se non si può trattenere lo spinlock, allora
120 ma potreste bloccarvi trattenendolo. Se non potete trattenere un mutex
121 il vostro processo si auto-sospenderà; verrà riattivato quando il mutex
124 permettervi di sospendere un processo (vedere
132 ----------------------------------------------
135 gli spinlock non esistono. Questa è un'ottima scelta di progettazione:
137 non c'è la necessità di avere un *lock*.
142 la prelazione equivalente ad un sistema multi-processore senza preoccuparci
146 ``CONFIG_PREEMPT`` abilitate, anche quando non avete un sistema
147 multi-processore, questo vi permetterà di identificare alcuni problemi
154 -----------------------------------
157 allora, per proteggerla, potete utilizzare un semplice mutex
174 ---------------------------------------------------
176 Se un softirq condivide dati col contesto utente, avete due problemi.
177 Primo, il contesto utente corrente potrebbe essere interroto da un softirq,
178 e secondo, la sezione critica potrebbe essere eseguita da un altro
182 l'opposto. (Il suffisso '_bh' è un residuo storico che fa riferimento al
183 "Bottom Halves", il vecchio nome delle interruzioni software. In un mondo
196 ------------------------------------------------
198 Questo caso è uguale al precedente, un tasklet viene eseguito da un softirq.
201 ----------------------------------------------
203 Anche questo caso è uguale al precedente, un timer viene eseguito da un
208 ------------------------------------
210 Qualche volta un tasklet od un timer potrebbero condividere i dati con
211 un altro tasklet o timer
216 Dato che un tasklet non viene mai eseguito contemporaneamente su due
218 più volte in contemporanea), perfino su sistemi multi-processore.
223 Se un altro tasklet/timer vuole condividere dati col vostro tasklet o timer,
226 in un tasklet ed avete la garanzia che nessun altro verrà eseguito sullo
230 ----------------------------
232 Spesso un softirq potrebbe condividere dati con se stesso o un tasklet/timer.
237 Lo stesso softirq può essere eseguito su un diverso processore: allo scopo
252 su un diverso processore.
254 .. _`it_hardirq-context`:
259 Solitamente le interruzioni hardware comunicano con un tasklet o un softirq.
261 preso in carico da un softirq.
264 ------------------------------------------------------------
266 Se un gestore di interruzioni hardware condivide dati con un softirq, allora
268 un'interruzione hardware, e secondo, la sezione critica potrebbe essere
269 eseguita da un'interruzione hardware su un processore diverso. Questo è il caso
276 hardware è in esecuzione: per questo si può usare spin_lock(), che è un po'
277 più veloce. L'unica eccezione è quando un altro gestore d'interruzioni
289 potrà essere utilizzato in un'interruzione hardware (dove le interruzioni sono
290 già disabilitate) e in un softirq (dove la disabilitazione delle interruzioni
294 da un'interruzione hardware, quindi spin_lock_irq() interrompe
300 --------------------------------------------------------
312 - Se siete in un contesto utente (una qualsiasi chiamata di sistema)
316 - Altrimenti (== i dati possono essere manipolati da un'interruzione) usate
319 - Evitate di trattenere uno spinlock per più di 5 righe di codice incluse
324 ----------------------------
328 da un processore per volta, quindi non ci sono requisiti per la
329 sincronizzazione (per esempio, un thread può essere eseguito solo su un
330 processore alla volta, ma se deve condividere dati con un altro thread, allora
334 spin_lock_irqsave(), che è un sovrainsieme di tutte le altre funzioni
354 +--------+----------------------------+
356 +--------+----------------------------+
358 +--------+----------------------------+
360 +--------+----------------------------+
362 +--------+----------------------------+
364 +--------+----------------------------+
371 Ci sono funzioni che provano a trattenere un *lock* solo una volta e
379 se ci riesce al primo colpo ritorna un valore diverso da zero, altrimenti
380 se fallisce ritorna 0. Questa funzione può essere utilizzata in un qualunque
385 ritorna un valore diverso da zero se è possibile trattenere il lock al primo
393 Guardiamo un semplice esempio: una memoria che associa nomi a numeri.
398 ------------------------
431 if (i->id == id) {
432 i->popularity++;
442 list_del(&obj->list);
444 cache_num--;
450 list_add(&obj->list, &cache);
454 if (!outcast || i->popularity < outcast->popularity)
466 return -ENOMEM;
468 strscpy(obj->name, name, sizeof(obj->name));
469 obj->id = id;
470 obj->popularity = 0;
488 int ret = -ENOENT;
494 strcpy(name, obj->name);
512 ---------------------------
515 dal contesto d'interruzione: sia hardware che software. Un esempio potrebbe
516 essere un timer che elimina oggetti dalla memoria.
518 Qui di seguito troverete la modifica nel formato *patch*: le righe ``-``
523 --- cache.c.usercontext 2003-12-09 13:58:54.000000000 +1100
524 +++ cache.c.interrupt 2003-12-09 14:07:49.000000000 +1100
525 @@ -12,7 +12,7 @@
529 -static DEFINE_MUTEX(cache_lock);
534 @@ -55,6 +55,7 @@
541 return -ENOMEM;
542 @@ -63,30 +64,33 @@
543 obj->id = id;
544 obj->popularity = 0;
546 - mutex_lock(&cache_lock);
549 - mutex_unlock(&cache_lock);
556 - mutex_lock(&cache_lock);
561 - mutex_unlock(&cache_lock);
568 int ret = -ENOENT;
571 - mutex_lock(&cache_lock);
576 strcpy(name, obj->name);
578 - mutex_unlock(&cache_lock);
584 se erano attive, altrimenti non farà niente (quando siamo già in un contesto
591 questa opzione deve diventare un parametro di cache_add().
594 ----------------------------------------
598 codice potrebbero avere un puntatore a questi oggetti piuttosto che cercarli
603 rende la sincronizzazione più complicata dato che non avviene più in un unico
606 Il secondo problema è il problema del ciclo di vita: se un'altra struttura
607 mantiene un puntatore ad un oggetto, presumibilmente si aspetta che questo
610 cache_delete() o peggio, aggiungere un oggetto che riutilizza lo
613 Dato che c'è un solo *lock*, non potete trattenerlo a vita: altrimenti
616 La soluzione a questo problema è l'uso di un contatore di riferimenti:
617 chiunque punti ad un oggetto deve incrementare il contatore, e decrementarlo
623 --- cache.c.interrupt 2003-12-09 14:25:43.000000000 +1100
624 +++ cache.c.refcnt 2003-12-09 14:33:05.000000000 +1100
625 @@ -7,6 +7,7 @@
633 @@ -17,6 +18,35 @@
639 + if (--obj->refcnt == 0)
645 + obj->refcnt++;
669 @@ -35,6 +65,7 @@
672 list_del(&obj->list);
674 cache_num--;
677 @@ -63,6 +94,7 @@
678 strscpy(obj->name, name, sizeof(obj->name));
679 obj->id = id;
680 obj->popularity = 0;
681 + obj->refcnt = 1; /* The cache holds a reference */
685 @@ -79,18 +111,15 @@
689 -int cache_find(int id, char *name)
693 - int ret = -ENOENT;
698 - if (obj) {
699 - ret = 0;
700 - strcpy(name, obj->name);
701 - }
705 - return ret;
714 Un altro punto da notare è che ho detto che il contatore dovrebbe incrementarsi
715 per ogni puntatore ad un oggetto: quindi il contatore di riferimenti è 1
717 non trattiene un riferimento per se, ma diventa più complicato.
723 Ci sono un certo numbero di operazioni atomiche definite
734 --- cache.c.refcnt 2003-12-09 15:00:35.000000000 +1100
735 +++ cache.c.refcnt-atomic 2003-12-11 15:49:42.000000000 +1100
736 @@ -7,7 +7,7 @@
740 - unsigned int refcnt;
745 @@ -18,33 +18,15 @@
749 -static void __object_put(struct object *obj)
750 -{
751 - if (--obj->refcnt == 0)
752 - kfree(obj);
753 -}
754 -
755 -static void __object_get(struct object *obj)
756 -{
757 - obj->refcnt++;
758 -}
759 -
762 - unsigned long flags;
763 -
764 - spin_lock_irqsave(&cache_lock, flags);
765 - __object_put(obj);
766 - spin_unlock_irqrestore(&cache_lock, flags);
767 + if (atomic_dec_and_test(&obj->refcnt))
773 - unsigned long flags;
774 -
775 - spin_lock_irqsave(&cache_lock, flags);
776 - __object_get(obj);
777 - spin_unlock_irqrestore(&cache_lock, flags);
778 + atomic_inc(&obj->refcnt);
782 @@ -65,7 +47,7 @@
785 list_del(&obj->list);
786 - __object_put(obj);
788 cache_num--;
791 @@ -94,7 +76,7 @@
792 strscpy(obj->name, name, sizeof(obj->name));
793 obj->id = id;
794 obj->popularity = 0;
795 - obj->refcnt = 1; /* The cache holds a reference */
796 + atomic_set(&obj->refcnt, 1); /* The cache holds a reference */
800 @@ -119,7 +101,7 @@
804 - __object_get(obj);
811 ---------------------------
817 - Si può togliere static da ``cache_lock`` e dire agli utenti che devono
818 trattenere il *lock* prima di modificare il nome di un oggetto.
820 - Si può fornire una funzione cache_obj_rename() che prende il
824 - Si può decidere che ``cache_lock`` protegge solo la memoria stessa, ed
825 un altro *lock* è necessario per la protezione del nome.
827 Teoricamente, possiamo avere un *lock* per ogni campo e per ogni oggetto.
830 - un *lock* che protegge l'infrastruttura (la lista ``cache`` di questo
833 - un *lock* che protegge l'infrastruttura (inclusi i puntatori alla lista
834 negli oggetti), e un *lock* nell'oggetto per proteggere il resto
837 - *lock* multipli per proteggere l'infrastruttura (per esempio un *lock*
838 per ogni lista), possibilmente con un *lock* per oggetto.
840 Qui di seguito un'implementazione con "un lock per oggetto":
844 --- cache.c.refcnt-atomic 2003-12-11 15:50:54.000000000 +1100
845 +++ cache.c.perobjectlock 2003-12-11 17:15:03.000000000 +1100
846 @@ -6,11 +6,17 @@
861 - int popularity;
865 @@ -77,6 +84,7 @@
866 obj->id = id;
867 obj->popularity = 0;
868 atomic_set(&obj->refcnt, 1); /* The cache holds a reference */
869 + spin_lock_init(&obj->lock);
886 Inoltre, da notare che ho aggiunto un commento che descrive i dati che sono
895 ----------------------------
897 Esiste un tipo di baco dove un pezzo di codice tenta di trattenere uno
904 Un caso un pochino più complesso; immaginate d'avere una spazio condiviso
905 fra un softirq ed il contesto utente. Se usate spin_lock() per
906 proteggerlo, il contesto utente potrebbe essere interrotto da un softirq
911 può succedere anche con un solo processore (Ma non sui sistemi
916 Questi casi sono facili da diagnosticare; sui sistemi multi-processore
921 Esiste un caso più complesso che è conosciuto come l'abbraccio della morte;
922 questo coinvolge due o più *lock*. Diciamo che avete un vettore di hash in cui
924 stesso hash. In un gestore di interruzioni software, dovete modificare un
925 oggetto e spostarlo su un altro hash; quindi dovrete trattenete lo spinlock
929 Qui abbiamo due problemi. Primo, se il vostro codice prova a spostare un
932 interruzione software su un altro processore sta tentando di spostare
933 un altro oggetto nella direzione opposta, potrebbe accadere quanto segue:
935 +---------------------------------+---------------------------------+
938 | Trattiene *lock* A -> OK | Trattiene *lock* B -> OK |
939 +---------------------------------+---------------------------------+
940 | Trattiene *lock* B -> attesa | Trattiene *lock* A -> attesa |
941 +---------------------------------+---------------------------------+
946 aspettando che l'altro lo rilasci. Sembra e puzza come un blocco totale.
949 --------------------
952 ordine non avrete mai un simile stallo. La pratica vi dirà che questo
953 approccio non funziona all'ingrandirsi del sistema: quando creo un nuovo
960 non tenterà mai di trattenere un altro *lock* quando lo ha già.
964 Un classico problema deriva dall'uso di *callback* e di *hook*: se li
965 chiamate mentre trattenete un *lock*, rischiate uno stallo o un abbraccio
971 Gli stalli sono un problema, ma non così terribile come la corruzione dei dati.
972 Un pezzo di codice trattiene un *lock* di lettura, cerca in una lista,
974 trattiene un *lock* di scrittura ed inserisce un oggetto; questo genere di
977 corsa fra temporizzatori: un passatempo del kernel
978 --------------------------------------------------
982 ha un temporizzatore che sta per distruggerlo.
984 Se volete eliminare l'intera collezione (diciamo quando rimuovete un modulo),
992 struct foo *next = list->next;
993 timer_delete(&list->timer);
1000 Primo o poi, questo esploderà su un sistema multiprocessore perché un
1014 struct foo *next = list->next;
1015 if (!timer_delete(&list->timer)) {
1026 Un altro problema è l'eliminazione dei temporizzatori che si riavviano
1028 Dato che questo è un problema abbastanza comune con una propensione
1032 Prima di rilasciare un temporizzatore dovreste chiamare la funzione
1041 la velocità d'esecuzione di un pezzo di codice che necessita di
1043 mentre qualcuno trattiene un *lock*. La seconda è il tempo necessario per
1044 acquisire (senza contese) e rilasciare un *lock*. La terza è di usare meno
1048 La concorrenza dipende da quanto a lungo un *lock* è trattenuto: dovreste
1049 trattenere un *lock* solo il tempo minimo necessario ma non un istante in più.
1054 Il tempo di acquisizione di un *lock* dipende da quanto danno fa
1058 corrente?): su sistemi multi-processore questa probabilità precipita
1059 rapidamente. Consideriamo un processore Intel Pentium III a 700Mhz: questo
1060 esegue un'istruzione in 0.7ns, un incremento atomico richiede 58ns, acquisire
1061 un *lock* che è nella memoria cache del processore richiede 160ns, e un
1062 trasferimento dalla memoria cache di un altro processore richiede altri
1066 Questi due obiettivi sono in conflitto: trattenere un *lock* per il minor
1068 parti (come nel nostro ultimo esempio con un *lock* per ogni oggetto),
1070 spesso è che tutto è più lento che con un singolo *lock*. Questo è un altro
1077 ------------------------
1094 --------------------------------------------
1096 Esiste un metodo di sincronizzazione per letture e scritture detto
1101 un'ottimizzazione.
1110 new->next = list->next;
1112 list->next = new;
1128 Rimuovere un elemento dalla lista è anche più facile: sostituiamo il puntatore
1134 list->next = old->next;
1150 l'elemento rimosso? Ricordate, un lettore potrebbe aver avuto accesso a questo
1168 dedurre che un qualsiasi lettore che abbia consultato la lista durante la
1170 codice RCU è un po' più ottimizzato di così, ma questa è l'idea di fondo.
1174 --- cache.c.perobjectlock 2003-12-11 17:15:03.000000000 +1100
1175 +++ cache.c.rcupdate 2003-12-11 17:55:14.000000000 +1100
1176 @@ -1,15 +1,18 @@
1186 - /* These two protected by cache_lock. */
1196 @@ -40,7 +43,7 @@
1200 - list_for_each_entry(i, &cache, list) {
1202 if (i->id == id) {
1203 i->popularity++;
1205 @@ -49,19 +52,25 @@
1219 - list_del(&obj->list);
1220 - object_put(obj);
1221 + list_del_rcu(&obj->list);
1222 cache_num--;
1223 + call_rcu(&obj->rcu, cache_delete_rcu);
1229 - list_add(&obj->list, &cache);
1230 + list_add_rcu(&obj->list, &cache);
1234 @@ -104,12 +114,11 @@
1238 - unsigned long flags;
1240 - spin_lock_irqsave(&cache_lock, flags);
1245 - spin_unlock_irqrestore(&cache_lock, flags);
1253 che ne abbiamo fatto qui, non ci interessano queste corse critiche perché un
1257 sincronizzazione con le altre funzioni, quindi è veloce su un sistema
1258 multi-processore tanto quanto lo sarebbe su un sistema mono-processore.
1260 Esiste un'ulteriore ottimizzazione possibile: vi ricordate il codice originale
1262 semplicemente tratteneva il *lock* prima di accedere ad un oggetto? Questo è
1263 ancora possibile: se trattenete un *lock* nessuno potrà cancellare l'oggetto,
1267 Ora, dato che il '*lock* di lettura' di un RCU non fa altro che disabilitare
1268 la prelazione, un chiamante che ha sempre la prelazione disabilitata fra le
1271 esporre la funzione __cache_find() dichiarandola non-static,
1276 molto più veloce su sistemi molti-processore grazie alla loro memoria cache.
1280 -------------------
1282 Un'altra tecnica comunemente usata per evitare la sincronizzazione è quella
1284 avere un contatore di qualcosa, potreste utilizzare uno spinlock ed un
1288 dimostrato che lo è devvero), potreste usare un contatore per ogni processore
1295 per-processore; su alcune architetture sono anche più efficienti
1298 Da notare che non esiste un modo facile ed affidabile per ottenere il valore
1299 di un simile contatore senza introdurre altri *lock*. In alcuni casi questo
1300 non è un problema.
1303 --------------------------------------------------------------
1311 se i dati vengono occasionalmente utilizzati da un contesto utente o
1312 da un'interruzione software. Il gestore d'interruzione non utilizza alcun
1323 un altro processore). Lo spinlock, invece, previene accessi simultanei.
1335 dovete necessariamente essere nel contesto utente: chiamarle da un
1339 ---------------------------
1345 aspettano d'essere chiamante da un contesto utente e quindi che possono
1348 - Accessi allo spazio utente:
1350 - copy_from_user()
1352 - copy_to_user()
1354 - get_user()
1356 - put_user()
1358 - kmalloc(GFP_KERNEL) <kmalloc>`
1360 - mutex_lock_interruptible() and
1364 Comunque, non deve essere usata in un contesto d'interruzione dato
1367 usata in un contesto d'interruzione perché un mutex deve essere rilasciato
1371 -------------------------------
1374 contesto, o trattenendo un qualsiasi *lock*.
1376 - printk()
1378 - kfree()
1380 - add_timer() e timer_delete()
1385 .. kernel-doc:: include/linux/mutex.h
1388 .. kernel-doc:: kernel/locking/mutex.c
1394 .. kernel-doc:: kernel/futex/core.c
1397 .. kernel-doc:: kernel/futex/futex.h
1400 .. kernel-doc:: kernel/futex/pi.c
1403 .. kernel-doc:: kernel/futex/requeue.c
1406 .. kernel-doc:: kernel/futex/waitwake.c
1412 - ``Documentation/locking/spinlocks.rst``: la guida di Linus Torvalds agli
1415 - Unix Systems for Modern Architectures: Symmetric Multiprocessing and
1421 per capire la sincronizzazione nei sistemi multi-processore.
1428 pulita e aggiunto un po' di stile.
1454 sostituiti dai tasklet. In un dato momento potrà esserci solo un
1462 Il kernel che esegue qualcosa per conto di un particolare processo (per
1463 esempio una chiamata di sistema) o di un thread del kernel. Potete
1469 Richiesta di interruzione hardware. in_hardirq() ritorna vero in un
1477 In soldoni, un softirq è uno delle 32 interruzioni software che possono
1482 (Uni-Processor) un solo processore, ovvero non è SMP. (``CONFIG_SMP=n``).
1484 multi-processore / SMP
1485 (Symmetric Multi-Processor) kernel compilati per sistemi multi-processore
1489 Un processo che esegue il proprio codice fuori dal kernel.
1492 Un'interruzione software registrabile dinamicamente che ha la garanzia
1493 d'essere eseguita solo su un processore alla volta.
1496 Un'interruzione software registrabile dinamicamente che viene eseguita
1497 (circa) in un determinato momento. Quando è in esecuzione è come un tasklet