SHOW:
|
|
- or go back to the newest paste.
1 | - | /* Q4 HUE HUE (ノ ゜Д゜)ノ ︵ ┻━┻ |
1 | + | |
2 | - | Francois "Rondoudou" Lebeau et Gabriel "Jesus Freak" Tessier */ |
2 | + | |
3 | Cette fonction est utilisée pour pour initialiser la librairie. Elle doit être | |
4 | - | /************************************************************************** |
4 | + | |
5 | - | Travail pratique No 2 : Thread utilisateurs |
5 | + | |
6 | - | |
6 | + | |
7 | - | Ce fichier est l'implémentation de la librarie des threads utilisateurs. |
7 | + | |
8 | - | |
8 | + | |
9 | - | Systemes d'explotation GLO-2001 |
9 | + | |
10 | - | Universite Laval, Quebec, Qc, Canada. |
10 | + | |
11 | - | (c) 2015 Philippe Giguere |
11 | + | |
12 | - | **************************************************************************/ |
12 | + | |
13 | - | #include <stdio.h> |
13 | + | |
14 | - | #include <stdlib.h> |
14 | + | |
15 | - | #include <unistd.h> |
15 | + | |
16 | - | #include <string.h> |
16 | + | |
17 | - | #include <ucontext.h> |
17 | + | |
18 | - | #include <time.h> |
18 | + | |
19 | - | #include "ThreadUtilisateur.h" |
19 | + | |
20 | gNTCB++; | |
21 | - | /* Définitions privées, donc pas dans le .h, car l'utilisateur n'a pas besoin de |
21 | + | |
22 | - | savoir ces détails d'implémentation. OBLIGATOIRE. */ |
22 | + | |
23 | - | typedef enum { |
23 | + | |
24 | - | THREAD_EXECUTE=0, |
24 | + | |
25 | - | THREAD_PRET, |
25 | + | |
26 | - | THREAD_BLOQUE, |
26 | + | |
27 | - | THREAD_TERMINE |
27 | + | |
28 | - | } EtatThread; |
28 | + | |
29 | return 1; | |
30 | - | #define TAILLE_PILE 4096 // Taille de la pile utilisée pour les threads |
30 | + | |
31 | return -1; | |
32 | - | /* Structure de données pour créer une liste chaînée simple sur les threads qui ont fait un join. |
32 | + | |
33 | - | Facultatif */ |
33 | + | |
34 | - | typedef struct WaitList { |
34 | + | |
35 | - | struct TCB *pThreadWaiting; |
35 | + | |
36 | - | struct WaitList *pNext; |
36 | + | |
37 | - | } WaitList; |
37 | + | |
38 | void (*fn)(void *) : une fonction fn qui sera le code exécuté par un thread. | |
39 | - | /* TCB : Thread Control Block. Cette structure de données est utilisée pour stocker l'information |
39 | + | |
40 | - | pour un thread. Elle permet aussi d'implémenter une liste doublement chaînée de TCB, ce qui |
40 | + | |
41 | - | facilite la gestion et permet de faire un ordonnanceur tourniquet sans grand effort. |
41 | + | |
42 | - | Facultatif. */ |
42 | + | |
43 | - | typedef struct TCB { // Important d'avoir le nom TCB ici, sinon le compilateur se plaint. |
43 | + | |
44 | - | tid id; // Numero du thread |
44 | + | |
45 | - | EtatThread etat; // Etat du thread |
45 | + | |
46 | - | ucontext_t ctx; // Endroit où stocker le contexte du thread |
46 | + | |
47 | - | struct TCB *pSuivant; // Liste doublement chaînée |
47 | + | |
48 | - | struct TCB *pPrecedant; // Liste doublement chaînée |
48 | + | |
49 | - | struct WaitList *pWaitListJoinedThreads; // Liste chaînée simple des threads en attente. |
49 | + | |
50 | - | int waitingCount; |
50 | + | |
51 | - | } TCB; |
51 | + | |
52 | thread->pWaitListJoinedThreads = malloc(sizeof(WaitList)); | |
53 | ||
54 | thread->id = gNextTID; | |
55 | ||
56 | gNextTID++; | |
57 | - | // Pour que les variables soient cachées à l'utilisateur, on va les déclarer static. Facultatif. |
57 | + | |
58 | - | static TCB *gpThreadCourant; //Thread en cours d'execution |
58 | + | |
59 | - | static int gNTCB = 0; |
59 | + | |
60 | - | static int gNextTID = 100; |
60 | + | |
61 | getcontext(&thread->ctx); | |
62 | thread->ctx.uc_stack.ss_sp = malloc(TAILLE_PILE); | |
63 | - | /* Cette fonction insère le TCB pToInsert dans la liste doublement chaînée, juste après |
63 | + | |
64 | - | pActual. */ |
64 | + | |
65 | - | int InsertTCBAfter(TCB *pActual, TCB *pToInsert) { |
65 | + | |
66 | - | // Mettre à jour le TCB précédent |
66 | + | |
67 | - | TCB *pNext = pActual->pSuivant; // pNext == thread 100 |
67 | + | |
68 | - | pActual->pSuivant = pToInsert; |
68 | + | |
69 | else | |
70 | - | // Mettre à jour le TCB inséré |
70 | + | |
71 | - | pToInsert->pSuivant = pNext; // pToInsert->pSuivant == 101 |
71 | + | |
72 | - | pToInsert->pPrecedant = pActual; |
72 | + | |
73 | - | |
73 | + | |
74 | - | // Et aussi celui après |
74 | + | |
75 | - | pNext->pPrecedant = pToInsert; |
75 | + | |
76 | d'ordonnacement) qui est prêt à être exécuté. L'ordonnancement se fait selon | |
77 | - | // On incrémente le nombre de TCB |
77 | + | |
78 | - | return ++gNTCB; |
78 | + | |
79 | états THREAD_BLOQUE ou THREAD_TERMINE. */ | |
80 | void ThreadCeder(void){ | |
81 | - | /* Cette fonction retire le TCB pActual de la liste doublement chaînée. */ |
81 | + | |
82 | - | int RemoveTCB(TCB *pActual) { |
82 | + | |
83 | - | // Mettre à jour le TCB inséré |
83 | + | |
84 | - | pActual->pSuivant->pPrecedant = pActual->pPrecedant; |
84 | + | |
85 | - | pActual->pPrecedant->pSuivant = pActual->pSuivant; |
85 | + | |
86 | - | // Mettre à jour le TCB inséré |
86 | + | |
87 | - | pActual->pSuivant = NULL; |
87 | + | |
88 | - | pActual->pPrecedant = NULL; |
88 | + | |
89 | - | |
89 | + | |
90 | - | // On décrémente le nombre de TCB |
90 | + | |
91 | - | return --gNTCB; |
91 | + | |
92 | { | |
93 | gpThreadCourant = gpThreadCourant->pSuivant; | |
94 | - | /* Cette fonction retourne le TCB correspondant au ThreadID fourni. */ |
94 | + | |
95 | - | TCB *GetPointerFromTid(tid ThreadID) { |
95 | + | |
96 | - | /* On inspecte la liste circulaire pour la traduction. Pas super rapide. */ |
96 | + | |
97 | - | int i; |
97 | + | |
98 | swapcontext(&threadCourant->ctx, &gpThreadCourant->ctx); | |
99 | - | TCB *pTCB = gpThreadCourant; |
99 | + | |
100 | - | for (i=0; i< gNTCB; i++) { |
100 | + | |
101 | - | if (pTCB->id == ThreadID) { return pTCB;} |
101 | + | |
102 | - | |
102 | + | |
103 | - | pTCB = pTCB->pSuivant; |
103 | + | |
104 | - | |
104 | + | |
105 | - | } |
105 | + | |
106 | - | return NULL; |
106 | + | |
107 | -1 si ThreadAJoindre n'existe pas | |
108 | -2 si ThreadAJoindre a déjà terminé (i.e. est dans l'état THREAD_TERMINE). | |
109 | - | char ThreadEtat(const EtatThread etat) { |
109 | + | |
110 | - | switch(etat){ |
110 | + | |
111 | - | case 0: |
111 | + | |
112 | - | return 'E'; |
112 | + | |
113 | - | case 1: |
113 | + | |
114 | - | return 'P'; |
114 | + | |
115 | - | case 2: |
115 | + | |
116 | - | return 'B'; |
116 | + | |
117 | - | case 3: |
117 | + | |
118 | - | return 'T'; |
118 | + | |
119 | { | |
120 | gpThreadCourant = gpThreadCourant->pSuivant; | |
121 | - | /*********************** CA C'EST LE POINT H CA LÀ LÀ ************************/ |
121 | + | |
122 | gpThreadCourant->etat = THREAD_BLOQUE; | |
123 | int i; | |
124 | for(i = 0; i < gpThreadCourant->waitingCount; i++) | |
125 | { | |
126 | TCBThreadAJoindre->pWaitListJoinedThreads->pThreadWaiting = TCBThreadAJoindre->pWaitListJoinedThreads->pNext->pThreadWaiting; // On trouve un espace libre pour ajouter un thread qui attend dans la waiting list | |
127 | } | |
128 | TCBThreadAJoindre->pWaitListJoinedThreads->pThreadWaiting = gpThreadCourant; // On dit que le thread main attend après ce thread (ThreadAJoindre) | |
129 | gpThreadCourant->waitingCount++; | |
130 | ThreadCeder(); | |
131 | return 1; | |
132 | } |