commit 72edb09925fb8363ece9b641a0b08d66fbaa2d02 Author: hiGepi Date: Wed Oct 19 09:02:34 2022 +0200 Depot 1 diff --git a/A1/2021-09-29_PolyReliability-smart.pdf b/A1/2021-09-29_PolyReliability-smart.pdf new file mode 100755 index 0000000..226e8f3 Binary files /dev/null and b/A1/2021-09-29_PolyReliability-smart.pdf differ diff --git a/A1/2021-11-24-slides.pdf b/A1/2021-11-24-slides.pdf new file mode 100755 index 0000000..b1d8e75 Binary files /dev/null and b/A1/2021-11-24-slides.pdf differ diff --git a/A1/DFA_DES/A1_10-12.ipynb b/A1/DFA_DES/A1_10-12.ipynb new file mode 100644 index 0000000..cd554e3 --- /dev/null +++ b/A1/DFA_DES/A1_10-12.ipynb @@ -0,0 +1,104 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Cours/TP 12/10/22 A1\n", + "\n", + "Injection de fautes, exploiter les failles.\n", + "Mecanismes cryptographiques, algo mathematiquement robustes. Quand on veut les implémenter, ils peuvent êtres soumis à différentes attaques.\n", + "\n", + "Attaque par injection de code. (Injecter des données, qui peuvent correspondre à du code donné, exploitation de bug dans le code logiciel)\n", + "Attaque par canaux auxiliaires. (temps d'execution, consommation elec, connexion)\n", + "\n", + "Raison d'optimisation (multiplication), multiplier par 0 -> pas de calcul, temps de calcul très long donc si secret = 0, temps de calcul court.\n", + "Attaque physique. (Ouvrir le circuit, sonder (microprobing) entre la mémoire et le processeur, FIB ?)\n", + "\n", + "Certaines attaques nécessitent le composant physique, d'autres à distances (marron et bleu p4)\n", + "Tirs lasers pour modifier la mémoire, injecter des fautes.\n", + "\n", + "\n", + "p9. nécessite une précision en cycle processeur très grande. Il faut cibler une ou quelques cycles.\n", + "p10. Algo plus connus/utilisé.\n", + "\n", + "Evaluation : QCM sur toutes les parties. (qu'est-ce qu'une attaque etc... Contres mesures et classification) Dans quel cas on utilise certaines contre mesure et dans cette attaque là quelle contre mesure utiliser ?\n", + "\n", + "p12. CRC pour protéger les CSP (critical security parameters) pour éviter de changer les p,q qui sont premiers.\n", + "\n", + "p14. On faute l'exposant d_i de proche en proche pour obtenir les m_i\n", + "p15. Contre mesure = rajouter un produit avec un nombre aléatoire (Stratégie Résilience)\n", + "\n", + "Vérification de valeur -> Stratégie détection\n", + "\n", + "p19. On déplace l'instant d'exécution de l'instruction sensible -> Observation de la consommation électrique\n", + "On peut rajouter des capteurs (lumière pour l'ouverture de la puce, f_clk pour le downclocking pour observer les signaux)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## TD\n", + "Q1 Donner l'équation de R_16 en fonction de R_15 et L_15\n", + "R_16 = L_15 ^ f(R_15,K_16) #f(.,.) p40\n", + "f(R_15,K_16) = P(S_1-8(E(R_15) ^ K_16))\n", + "\n", + "Q2 Entrée R_15 fautée : R_15'\n", + "R_16' = L_15' ^ P(S_1-8(E(R_15') ^ K_16))\n", + "\n", + "Q3 Delta(R_16) = R_16 ^ R_16'\n", + "= Delta(L_15) ^ P(a) ^ P(b)\n", + "= Delta(L_15) ^ P(S_1-8(E(R_15) ^ K_16) ^ S_1-8(E(R_15') ^ K_16))\n", + "\n", + "Q4\n", + "Connues : R_16, R_15 = L_16 et R_15' = L_16'\n", + "Inconnues : Delta(L_15) et K_16\n", + "\n", + "On veut Delta(L_15) = 0 donc ne pas toucher L_15 lors de la faute.\n", + "\n", + "Q5\n", + "P⁻¹(Delta(R_16)) = S_1-8(E(R_15) ^ K_16) ^ S_1-8(E(R_15') ^ K_16)\n", + "\n", + "On teste les clés K_16 pour avoir égalité des deux côtés, si elle c'est vérifié, la clé est une candidate." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Défi 4 :\n", + "\n", + "Q1 \n", + "P⁻¹_1(Delta(R_16)) = S_1(E(R_15) ^ K_16,1) ^ S_1(E(R_15') ^ K_16,1)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2.7.18 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "2.7.18" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "f92b2924b84ff19c1c3dc485f7644d4486f64738191026bf8e6de303969141b5" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/A1/DFA_DES/DFA_DES_challenges.pyc b/A1/DFA_DES/DFA_DES_challenges.pyc new file mode 100644 index 0000000..66dc63e Binary files /dev/null and b/A1/DFA_DES/DFA_DES_challenges.pyc differ diff --git a/A1/DFA_DES/DFA_DES_elev.py b/A1/DFA_DES/DFA_DES_elev.py new file mode 100644 index 0000000..a509c80 --- /dev/null +++ b/A1/DFA_DES/DFA_DES_elev.py @@ -0,0 +1,12 @@ +# @file DFA_DES_elev.py +# @brief Sandbox for DFA-on-DES's challenges. +# @author Laurent Sauvage + +from DFA_DES_challenges import * +from des_block import * + +if __name__ == "__main__": + + # === Challenge #1 : Simple Fault Analysis === + for c1, c2 in CHALLENGE[4]: + print (c1, c2) diff --git a/A1/DFA_DES/des_block.pyc b/A1/DFA_DES/des_block.pyc new file mode 100644 index 0000000..c6ed4da Binary files /dev/null and b/A1/DFA_DES/des_block.pyc differ diff --git a/A1/DFA_DES/des_block_demo.py b/A1/DFA_DES/des_block_demo.py new file mode 100644 index 0000000..5ff9791 --- /dev/null +++ b/A1/DFA_DES/des_block_demo.py @@ -0,0 +1,38 @@ +# @file des_block_demo.py +# @brief How to use des_block class. +# @author Laurent Sauvage + +from des_block import * + +KSHIFTS= ( 0, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 ) + +if __name__ == "__main__": + + #======================================== + P= des_block("0x0123456789abcdef", 64) # Create a 64-bit wide DES block + print ("P={} (hex) {} (dec)".format(P, P.value())) + #======================================== + L0, R0= P.ip() # Initial permutation + print ("L0= {} Ro={}".format(L0, R0)) + invip_ip_P= L0.concat(R0).ip(-1) # Inverse of Initial permutation + print ("invip_ip_P=", invip_ip_P) + print ("diff=", P.xor(invip_ip_P)) + #======================================== + KEY= des_block("0xfedcba9876543210", 64) # Create a 64-bit wide DES block + print ("Master KEY=", KEY) + pc1_KEY= KEY.pc1() # @note Inverse of pc1() = pc1(-1) + C0= pc1_KEY.subblock( 0, 28) + D0= pc1_KEY.subblock(28, 56) + C1= C0.ls(KSHIFTS[1]) # @note Left shift of n : ls(n) + # Inverse of left shift : rs(n) + # KSHIFTS[r] = number of shifts for round r + D1= D0.ls(KSHIFTS[1]) + K1= C1.concat(D1).pc2() # @note Inverse of pc2() = pc2(-1) + print ("Round Key K1=", K1) + #======================================== + inS= R0.e().xor(K1) + outS= des_block() + for i in range(0, 8): # for Sbox from 0 to 7 + outS= outS.concat( inS.subblock(6*i, 6*i+6).s(i) ) + R1= outS.p().xor(L0) # @note Inverse of p() : p(-1) + print ("R1=", R1) diff --git a/A1/DFA_DES/fips46-3.pdf b/A1/DFA_DES/fips46-3.pdf new file mode 100644 index 0000000..19c3644 Binary files /dev/null and b/A1/DFA_DES/fips46-3.pdf differ diff --git a/A1/couterfeiting_hth.pdf b/A1/couterfeiting_hth.pdf new file mode 100644 index 0000000..307e694 Binary files /dev/null and b/A1/couterfeiting_hth.pdf differ diff --git a/A1/dfa_destar_ b/A1/dfa_destar_ new file mode 100644 index 0000000..f786c6f Binary files /dev/null and b/A1/dfa_destar_ differ diff --git a/A1/fia_lect_handout_v2019-04-24.pdf b/A1/fia_lect_handout_v2019-04-24.pdf new file mode 100644 index 0000000..abdcf8d Binary files /dev/null and b/A1/fia_lect_handout_v2019-04-24.pdf differ diff --git a/A1/puf.pdf b/A1/puf.pdf new file mode 100644 index 0000000..e8c261a Binary files /dev/null and b/A1/puf.pdf differ diff --git a/A1/reverse_engineering_hw.pdf b/A1/reverse_engineering_hw.pdf new file mode 100644 index 0000000..1bb8ef3 Binary files /dev/null and b/A1/reverse_engineering_hw.pdf differ diff --git a/A1/seti901-2021-countermeasures.pdf b/A1/seti901-2021-countermeasures.pdf new file mode 100644 index 0000000..14424ca Binary files /dev/null and b/A1/seti901-2021-countermeasures.pdf differ diff --git a/A1/seti901-2021-sca.pdf b/A1/seti901-2021-sca.pdf new file mode 100644 index 0000000..42aa913 Binary files /dev/null and b/A1/seti901-2021-sca.pdf differ diff --git a/A1/trng.pdf b/A1/trng.pdf new file mode 100644 index 0000000..3cf37ea Binary files /dev/null and b/A1/trng.pdf differ diff --git a/A2/Arteris_FlexNoC_presentation.pdf b/A2/Arteris_FlexNoC_presentation.pdf new file mode 100755 index 0000000..658ff2e Binary files /dev/null and b/A2/Arteris_FlexNoC_presentation.pdf differ diff --git a/A2/Cours_Low-Power-Techniques-M2-SETI_v13122021.pdf b/A2/Cours_Low-Power-Techniques-M2-SETI_v13122021.pdf new file mode 100755 index 0000000..2173898 Binary files /dev/null and b/A2/Cours_Low-Power-Techniques-M2-SETI_v13122021.pdf differ diff --git a/A4/TP_seuillage.pdf b/A4/TP_seuillage.pdf new file mode 100755 index 0000000..2c88d20 Binary files /dev/null and b/A4/TP_seuillage.pdf differ diff --git a/A4/multicore1.pdf b/A4/multicore1.pdf new file mode 100755 index 0000000..195b24a Binary files /dev/null and b/A4/multicore1.pdf differ diff --git a/A4/multicore2.pdf b/A4/multicore2.pdf new file mode 100755 index 0000000..1b1ee2c Binary files /dev/null and b/A4/multicore2.pdf differ diff --git a/A4/tp-openmp.pdf b/A4/tp-openmp.pdf new file mode 100755 index 0000000..ab69129 Binary files /dev/null and b/A4/tp-openmp.pdf differ diff --git a/B1/2021_10_20_WCET-IPET-STR-18.pdf b/B1/2021_10_20_WCET-IPET-STR-18.pdf new file mode 100755 index 0000000..698e05b Binary files /dev/null and b/B1/2021_10_20_WCET-IPET-STR-18.pdf differ diff --git a/B1/Cours_1.pdf b/B1/Cours_1.pdf new file mode 100755 index 0000000..53a00fd Binary files /dev/null and b/B1/Cours_1.pdf differ diff --git a/B1/Cours_2.pdf b/B1/Cours_2.pdf new file mode 100755 index 0000000..08f8f0b Binary files /dev/null and b/B1/Cours_2.pdf differ diff --git a/B1/Cours_3_IMA.pdf b/B1/Cours_3_IMA.pdf new file mode 100755 index 0000000..aac93e1 Binary files /dev/null and b/B1/Cours_3_IMA.pdf differ diff --git a/B1/Cours_3_rt-bus.pdf b/B1/Cours_3_rt-bus.pdf new file mode 100755 index 0000000..da908e0 Binary files /dev/null and b/B1/Cours_3_rt-bus.pdf differ diff --git a/B1/TD-IPET-STREC.pdf b/B1/TD-IPET-STREC.pdf new file mode 100755 index 0000000..e7ef0d3 Binary files /dev/null and b/B1/TD-IPET-STREC.pdf differ diff --git a/B1/TD1-RTS-v71.pdf b/B1/TD1-RTS-v71.pdf new file mode 100755 index 0000000..a0df70a Binary files /dev/null and b/B1/TD1-RTS-v71.pdf differ diff --git a/B1/annales/astre-strec-2017v1.pdf b/B1/annales/astre-strec-2017v1.pdf new file mode 100755 index 0000000..82c958e Binary files /dev/null and b/B1/annales/astre-strec-2017v1.pdf differ diff --git a/B1/annales/comasic-seti-2016-p1v3-1.pdf b/B1/annales/comasic-seti-2016-p1v3-1.pdf new file mode 100755 index 0000000..79f6917 Binary files /dev/null and b/B1/annales/comasic-seti-2016-p1v3-1.pdf differ diff --git a/B1/annales/comasic-seti-2017v1.pdf b/B1/annales/comasic-seti-2017v1.pdf new file mode 100755 index 0000000..9b70552 Binary files /dev/null and b/B1/annales/comasic-seti-2017v1.pdf differ diff --git a/B1/cours3.md b/B1/cours3.md new file mode 100644 index 0000000..8cfa408 --- /dev/null +++ b/B1/cours3.md @@ -0,0 +1,4 @@ +# Cours 12/10 + +Niveau de criticalité : tolérance de fautes, fautes critiques + diff --git a/B1/goossens-2013.pdf b/B1/goossens-2013.pdf new file mode 100755 index 0000000..2e427ba Binary files /dev/null and b/B1/goossens-2013.pdf differ diff --git a/D3/TP/SETI_2021-2022_TP1_Kmeans.pdf b/D3/TP/SETI_2021-2022_TP1_Kmeans.pdf new file mode 100755 index 0000000..780930b Binary files /dev/null and b/D3/TP/SETI_2021-2022_TP1_Kmeans.pdf differ diff --git a/D3/TP/SETI_2021-2022_TP2_MLP.pdf b/D3/TP/SETI_2021-2022_TP2_MLP.pdf new file mode 100755 index 0000000..7c36c7f Binary files /dev/null and b/D3/TP/SETI_2021-2022_TP2_MLP.pdf differ diff --git a/D3/TP/SETI_2021-2022_TP3_SVM.pdf b/D3/TP/SETI_2021-2022_TP3_SVM.pdf new file mode 100755 index 0000000..a24f74f Binary files /dev/null and b/D3/TP/SETI_2021-2022_TP3_SVM.pdf differ diff --git a/D3/TP/TP1.ipynb b/D3/TP/TP1.ipynb new file mode 100644 index 0000000..de44a46 --- /dev/null +++ b/D3/TP/TP1.ipynb @@ -0,0 +1,156 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# TP1 KMEANS\n", + "\n", + "On nous propose de coder l'algorithme des kmeans afin de faire du clustering sur 2 classes puis plus de 2 classes.\n", + "Plus tard, on utilisera notre algorithme pour segmenter une image sur l'information de couleur." + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import scipy" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": {}, + "outputs": [], + "source": [ + "mean = [1,2]\n", + "sd = [0.25, 0.25]\n", + "dim = 2\n", + "nb = 100\n", + "clusters = 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Fonctions utiles pour le script" + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": {}, + "outputs": [], + "source": [ + "def gen_points(mean=1,sd=0.5, nb=100, dim=2, clusters=2):\n", + " size = []\n", + " for i in range(0,dim):\n", + " size.append(nb)\n", + " size.append(clusters)\n", + " points = np.random.normal(mean,sd,size=size)\n", + " return points" + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "metadata": {}, + "outputs": [], + "source": [ + "def distance(points,dim=2): \n", + " return scipy.spatial.distance.cdist(points)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Fonctions à utiliser pour le clustering" + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "metadata": {}, + "outputs": [], + "source": [ + "def kmeans(points = [0,0], K = 1):\n", + " print(\"hi\")" + ] + }, + { + "cell_type": "code", + "execution_count": 99, + "metadata": {}, + "outputs": [], + "source": [ + "def visualisation(points, pos_cluster=0, dim=2):\n", + " if(dim==2):\n", + " plt.plot(points[0], points[1], 'o')\n", + " plt.grid(True)\n", + " plt.axis([0,3,0,3])" + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[100, 100, 2]\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "points = gen_points(mean,sd,nb,dim,clusters)\n", + "visualisation(points, dim=dim)\n", + "# kmeans()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.10 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Presentation-SETI-rentree-2021.pdf b/Presentation-SETI-rentree-2021.pdf new file mode 100755 index 0000000..b19faeb Binary files /dev/null and b/Presentation-SETI-rentree-2021.pdf differ diff --git a/RAN_CPP/M1IST-443-2019partiel.pdf b/RAN_CPP/M1IST-443-2019partiel.pdf new file mode 100755 index 0000000..c0fceff Binary files /dev/null and b/RAN_CPP/M1IST-443-2019partiel.pdf differ diff --git a/RAN_CPP/cours1-intro-eleves-gs.pdf b/RAN_CPP/cours1-intro-eleves-gs.pdf new file mode 100755 index 0000000..e170737 Binary files /dev/null and b/RAN_CPP/cours1-intro-eleves-gs.pdf differ diff --git a/RAN_CPP/man_cpp2013.pdf b/RAN_CPP/man_cpp2013.pdf new file mode 100755 index 0000000..5e9a95b Binary files /dev/null and b/RAN_CPP/man_cpp2013.pdf differ diff --git a/T1/A_Simple_Project_Paradigm_for_Teaching_Computer_Ar.pdf b/T1/A_Simple_Project_Paradigm_for_Teaching_Computer_Ar.pdf new file mode 100644 index 0000000..ec4eaf6 Binary files /dev/null and b/T1/A_Simple_Project_Paradigm_for_Teaching_Computer_Ar.pdf differ diff --git a/T1/Cours.md b/T1/Cours.md new file mode 100644 index 0000000..c3dfef1 --- /dev/null +++ b/T1/Cours.md @@ -0,0 +1,18 @@ +# Cours T1 architecture des processeurs + +## 13/10 + +### T1-C1 +p64 : +Attention aux capacités des FPGA qui sont dans des conditions très favorables et difficilement atteignables. + +### T1-C2 + +Avantage harvard : accès plus rapide à instruction et données + +p6. temps exécution = nombre instruction * temps moyen par instruction * temps cycle + +p8. instructions simples, donc décomposition des instructions complexes en instructions simples. + +### T1-C3 Pipeline + diff --git a/T1/RAN/M1-00-tr-codage.pdf b/T1/RAN/M1-00-tr-codage.pdf new file mode 100755 index 0000000..a153788 Binary files /dev/null and b/T1/RAN/M1-00-tr-codage.pdf differ diff --git a/T1/RAN/M1-01-tr-add.pdf b/T1/RAN/M1-01-tr-add.pdf new file mode 100755 index 0000000..d1432cd Binary files /dev/null and b/T1/RAN/M1-01-tr-add.pdf differ diff --git a/T1/RAN/M1-02-tr-mult.pdf b/T1/RAN/M1-02-tr-mult.pdf new file mode 100755 index 0000000..2325cce Binary files /dev/null and b/T1/RAN/M1-02-tr-mult.pdf differ diff --git a/T1/RAN/M1-03-tr-div.pdf b/T1/RAN/M1-03-tr-div.pdf new file mode 100755 index 0000000..2500eaa Binary files /dev/null and b/T1/RAN/M1-03-tr-div.pdf differ diff --git a/T1/RAN/M1-04-tr-float.pdf b/T1/RAN/M1-04-tr-float.pdf new file mode 100755 index 0000000..dcad8bc Binary files /dev/null and b/T1/RAN/M1-04-tr-float.pdf differ diff --git a/T1/RAN/M1-06-tr-archi-g.pdf b/T1/RAN/M1-06-tr-archi-g.pdf new file mode 100755 index 0000000..a270cf2 Binary files /dev/null and b/T1/RAN/M1-06-tr-archi-g.pdf differ diff --git a/T1/RAN/M1-07-tr-nios.pdf b/T1/RAN/M1-07-tr-nios.pdf new file mode 100755 index 0000000..3feac32 Binary files /dev/null and b/T1/RAN/M1-07-tr-nios.pdf differ diff --git a/T1/RAN/M1-08-tr-nios-non-pipeline.pdf b/T1/RAN/M1-08-tr-nios-non-pipeline.pdf new file mode 100755 index 0000000..cf05a48 Binary files /dev/null and b/T1/RAN/M1-08-tr-nios-non-pipeline.pdf differ diff --git a/T1/RAN/M1-09-tr-nios-pipeline.pdf b/T1/RAN/M1-09-tr-nios-pipeline.pdf new file mode 100755 index 0000000..943f1f4 Binary files /dev/null and b/T1/RAN/M1-09-tr-nios-pipeline.pdf differ diff --git a/T1/RAN/M1-10-tr-cache.pdf b/T1/RAN/M1-10-tr-cache.pdf new file mode 100755 index 0000000..0546dca Binary files /dev/null and b/T1/RAN/M1-10-tr-cache.pdf differ diff --git a/T1/RAN/M1-11-tr-avance.pdf b/T1/RAN/M1-11-tr-avance.pdf new file mode 100755 index 0000000..208e1a7 Binary files /dev/null and b/T1/RAN/M1-11-tr-avance.pdf differ diff --git a/T1/T1-01-intro.pdf b/T1/T1-01-intro.pdf new file mode 100755 index 0000000..f2819fc Binary files /dev/null and b/T1/T1-01-intro.pdf differ diff --git a/T1/T1-02-jeux-instructions.pdf b/T1/T1-02-jeux-instructions.pdf new file mode 100755 index 0000000..5a1ae51 Binary files /dev/null and b/T1/T1-02-jeux-instructions.pdf differ diff --git a/T1/T1-03-pipe.pdf b/T1/T1-03-pipe.pdf new file mode 100755 index 0000000..3caf5e4 Binary files /dev/null and b/T1/T1-03-pipe.pdf differ diff --git a/T1/T1-04-ilp.pdf b/T1/T1-04-ilp.pdf new file mode 100755 index 0000000..e35a093 Binary files /dev/null and b/T1/T1-04-ilp.pdf differ diff --git a/T1/T1-05-cache.pdf b/T1/T1-05-cache.pdf new file mode 100755 index 0000000..20cf045 Binary files /dev/null and b/T1/T1-05-cache.pdf differ diff --git a/T1/T1-06-optim.pdf b/T1/T1-06-optim.pdf new file mode 100755 index 0000000..032d35d Binary files /dev/null and b/T1/T1-06-optim.pdf differ diff --git a/T1/T1-C1.pdf b/T1/T1-C1.pdf new file mode 100644 index 0000000..3fcaf86 Binary files /dev/null and b/T1/T1-C1.pdf differ diff --git a/T1/T1-TD1-corr.pdf b/T1/T1-TD1-corr.pdf new file mode 100755 index 0000000..8ee3d1c Binary files /dev/null and b/T1/T1-TD1-corr.pdf differ diff --git a/T1/T1-TD1.pdf b/T1/T1-TD1.pdf new file mode 100755 index 0000000..30c93df Binary files /dev/null and b/T1/T1-TD1.pdf differ diff --git a/T1/T1-TD2-corr.pdf b/T1/T1-TD2-corr.pdf new file mode 100755 index 0000000..2d05e27 Binary files /dev/null and b/T1/T1-TD2-corr.pdf differ diff --git a/T1/T1-TD2.pdf b/T1/T1-TD2.pdf new file mode 100755 index 0000000..14a023f Binary files /dev/null and b/T1/T1-TD2.pdf differ diff --git a/T1/ex-dec20b-corr.pdf b/T1/ex-dec20b-corr.pdf new file mode 100755 index 0000000..b550669 Binary files /dev/null and b/T1/ex-dec20b-corr.pdf differ diff --git a/T1/ex-dec20b.pdf b/T1/ex-dec20b.pdf new file mode 100755 index 0000000..6e4dba6 Binary files /dev/null and b/T1/ex-dec20b.pdf differ diff --git a/T1/ex-dec20c.pdf b/T1/ex-dec20c.pdf new file mode 100755 index 0000000..13c53ac Binary files /dev/null and b/T1/ex-dec20c.pdf differ diff --git a/T1/tp1.pdf b/T1/tp1.pdf new file mode 100755 index 0000000..0abe7eb Binary files /dev/null and b/T1/tp1.pdf differ diff --git a/T1/tp2.pdf b/T1/tp2.pdf new file mode 100755 index 0000000..5391c1c Binary files /dev/null and b/T1/tp2.pdf differ diff --git a/T1/tp3-programmes.zip b/T1/tp3-programmes.zip new file mode 100755 index 0000000..d9cb58f Binary files /dev/null and b/T1/tp3-programmes.zip differ diff --git a/T1/tp3.pdf b/T1/tp3.pdf new file mode 100755 index 0000000..3473648 Binary files /dev/null and b/T1/tp3.pdf differ diff --git a/T2/Corrigé- Examen T2 _ 20211130_ LOUISE Stéphane.pdf b/T2/Corrigé- Examen T2 _ 20211130_ LOUISE Stéphane.pdf new file mode 100755 index 0000000..ddaef3c Binary files /dev/null and b/T2/Corrigé- Examen T2 _ 20211130_ LOUISE Stéphane.pdf differ diff --git a/T2/Petri-1.pdf b/T2/Petri-1.pdf new file mode 100644 index 0000000..d0237fd Binary files /dev/null and b/T2/Petri-1.pdf differ diff --git a/T2/T1_Cours.ipynb b/T2/T1_Cours.ipynb new file mode 100644 index 0000000..105a79d --- /dev/null +++ b/T2/T1_Cours.ipynb @@ -0,0 +1,119 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Cours\n", + "\n", + "## V. David 18/10\n", + "\n", + "Correction robot atelier d'assemblage\n", + "\n", + "Proposition de la classe :" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "deposer():\n", + " P(RB)\n", + " Examiner()\n", + "\n", + " if(il_faut_tourner):\n", + " P(RA)\n", + " tourner()\n", + " V(RA)\n", + "\n", + " poser_la_piece()\n", + " V(RB)\n", + "\n", + "prendre():\n", + " P(RA)\n", + " Examiner()\n", + "\n", + " if(il_faut_tourner)\n", + " P(RB)\n", + " tourner()\n", + " V(RB)\n", + "\n", + " enlever_la_piece()\n", + " V(RA)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Correction de la proposition :\n", + "Vérifier que les actions fonctionnent, puis vérifier les deadlocks\n", + "Remède deadlock p23 : désymétriser les codes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "P(S_libre)\n", + "deposer():\n", + " P(RB)\n", + " Examiner()\n", + "\n", + " if(il_faut_tourner):\n", + " V(RB)\n", + " P(RA)\n", + " P(RB)\n", + "\n", + " examiner()\n", + " if(il_faut_tourner):\n", + " tourner()\n", + "\n", + " V(RA)\n", + "\n", + " poser_la_piece()\n", + " V(RB)\n", + "V(S_occupe)\n", + "\n", + "\n", + "P(S_occupe)\n", + "prendre():\n", + " P(RA)\n", + " Examiner()\n", + "\n", + " if(il_faut_tourner)\n", + " P(RB)\n", + " tourner()\n", + " V(RB)\n", + "\n", + " enlever_la_piece()\n", + " V(RA)\n", + "V(S_libre)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.10 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.8.10" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/T2/atelier_assemblage.txt b/T2/atelier_assemblage.txt new file mode 100755 index 0000000..1296c1f --- /dev/null +++ b/T2/atelier_assemblage.txt @@ -0,0 +1,20 @@ +// Faire fin diapo 1 p26 exo avec sémaphores + +RA(){ + deposer() + examiner() + + if(... tourner()){ + tourner + } + + poser_la_piece() +} + +RB(){ + examiner() + if(... tourner()){ + tourner + } + enlever_la_piece() +} \ No newline at end of file diff --git a/T2/petri-impr.pdf b/T2/petri-impr.pdf new file mode 100644 index 0000000..6810802 Binary files /dev/null and b/T2/petri-impr.pdf differ diff --git a/T2/pipe.jpg b/T2/pipe.jpg new file mode 100755 index 0000000..1148980 Binary files /dev/null and b/T2/pipe.jpg differ diff --git a/T2/pipe_semaphore.txt b/T2/pipe_semaphore.txt new file mode 100755 index 0000000..09c722d --- /dev/null +++ b/T2/pipe_semaphore.txt @@ -0,0 +1,30 @@ +int L = N; +int O = @; + +write(){ + P(L); + tab[ilibre] = V; + ilibre++; + if(ilibre==N) iLibre = @; + + V(O); +} + + +read(){ + P(O); + V = tab[ioccupe]; + ioccupe++; + if(ioccupe==N) ioccupe = @; + + V(L); +} + +// Problème d'indice en fonction de qui écrit en premier, +puis problème de si on fini de lire avant de finir d'écrire sur la bonne case + +multREAD() + var j; + P(O); + P(COM3); + j = tabTransiOcc[j \ No newline at end of file diff --git a/T2/robo-exercice.pdf b/T2/robo-exercice.pdf new file mode 100644 index 0000000..ab556fe Binary files /dev/null and b/T2/robo-exercice.pdf differ diff --git a/T2/robots.pdf b/T2/robots.pdf new file mode 100755 index 0000000..9d2692a Binary files /dev/null and b/T2/robots.pdf differ diff --git a/T2/tp.pdf b/T2/tp.pdf new file mode 100755 index 0000000..221d4b2 Binary files /dev/null and b/T2/tp.pdf differ diff --git a/T2/tp/Makefile b/T2/tp/Makefile new file mode 100755 index 0000000..4a58bb6 --- /dev/null +++ b/T2/tp/Makefile @@ -0,0 +1,44 @@ +.POSIX: +CC = cc +CFLAGS = -std=c11 -Wall -Wextra -O3 -mcx16 -pthread #-DDEBUG +LDFLAGS = -pthread +#LDLIBS = -latomic + +C= $(wildcard *.c) +H= $(wildcard *.h) +PREAMBULE_SRCS := preambule.c +POSIX_SRCS := $(filter-out %preambule.c %Atomic.c %TestAndSet.c, $(C)) +ATOMIC_SRCS := $(filter-out %preambule.c %POSIX.c %TestAndSet.c, $(C)) +TESTANDSET_SRCS := $(filter-out %preambule.c %POSIX.c %Atomic.c, $(C)) +DEPS= $(H:.h) +PREAMBULE_OBJS= $(PREAMBULE_SRCS:.c=.o) +POSIX_OBJS= $(POSIX_SRCS:.c=.o) +ATOMIC_OBJS= $(ATOMIC_SRCS:.c=.o) +TESTANDSET_OBJS= $(TESTANDSET_SRCS:.c=.o) + +preambule: $(PREAMBULE_OBJS) $(DEPS) + $(CC) $(LDFLAGS) -o preambule $(PREAMBULE_OBJS) $(LDLIBS) + +posix: $(POSIX_OBJS) $(DEPS) + $(CC) $(LDFLAGS) -o mySoftwarePosix $(POSIX_OBJS) $(LDLIBS) + +atomic: $(ATOMIC_OBJS) $(DEPS) + $(CC) $(LDFLAGS) -o mySoftwareAtomic $(ATOMIC_OBJS) $(LDLIBS) + +testandset: $(TESTANDSET_OBJS) $(DEPS) + $(CC) $(LDFLAGS) -o mySoftwareTestAndSet $(TESTANDSET_OBJS) $(LDLIBS) + +clean: + rm -f preambule mySoftwarePosix mySoftwareAtomic mySoftwareTestAndSet $(PREAMBULE_OBJS) $(POSIX_OBJS) $(ATOMIC_OBJS) $(TESTANDSET_OBJS) + +runpreambule: clean preambule + ./preambule + +runposix: clean posix + ./mySoftwarePosix + +runatomic: clean atomic + ./mySoftwareAtomic + +runtestandset: clean testandset + ./mySoftwareTestAndSet \ No newline at end of file diff --git a/T2/tp/acquisitionManager.h b/T2/tp/acquisitionManager.h new file mode 100755 index 0000000..72bf728 --- /dev/null +++ b/T2/tp/acquisitionManager.h @@ -0,0 +1,26 @@ +#ifndef ACQUISITION_MANAGER_H +#define ACQUISITION_MANAGER_H + +#include "msg.h" + +/** + * Initializes the acquisitions + */ +unsigned int acquisitionManagerInit(void); + +/** + * Waits that acquisitions terminate + */ +void acquisitionManagerJoin(void); + +/** + * Get producer count (debug output) + */ +unsigned int getProducerCount(void); + +/** + * Get new message (blocking) + */ +void getMessage(volatile MSG_BLOCK* mBlock); + +#endif diff --git a/T2/tp/acquisitionManagerPOSIX.c b/T2/tp/acquisitionManagerPOSIX.c new file mode 100755 index 0000000..ca2d009 --- /dev/null +++ b/T2/tp/acquisitionManagerPOSIX.c @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include +#include +#include "acquisitionManager.h" +#include "msg.h" +#include "iSensor.h" +#include "mySoftware.h" +#include "iAcquisitionManager.h" +#include "debug.h" + + +//producer count storage +volatile unsigned int produceCount = 0; + +pthread_t producers[4]; + +static void *produce(void *ithread); + +/** +* Semaphores and Mutex +*/ +pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; + +// Ring buffer +MSG_BLOCK buffer[100]; +unsigned int buf_head = 0; +unsigned int buf_tail = 0; + +/* +* Creates the synchronization elements. +* @return ERROR_SUCCESS if the init is ok, ERROR_INIT otherwise +*/ +static unsigned int createSynchronizationObjects(void); + +/* +* Increments the produce count. +*/ +static void incrementProducerCount(void); + +static unsigned int createSynchronizationObjects(void) +{ + //TODO + printf("[acquisitionManager]Semaphore created\n"); + return ERROR_SUCCESS; +} + +static void incrementProducerCount(void) +{ + pthread_mutex_lock(&m1); + produceCount++; + pthread_mutex_unlock(&m1); +} + +unsigned int getProducerCount(void) +{ + unsigned int p = 0; + pthread_mutex_lock(&m1); + p = produceCount; + pthread_mutex_unlock(&m1); + return p; +} + +void getMessage(volatile MSG_BLOCK* mBlock) { + volatile MSG_BLOCK msg; + char done = 0; + + // Voir TD Vincent David + // Là c'est une version de personne frustrée ne correspondant pas au TD + while (!done) { + pthread_mutex_lock(&m1); + if (buf_tail > buf_head) { + msg = buffer[buf_tail]; + buf_tail++; + done = 1; + } + pthread_mutex_unlock(&m1); + } + *mBlock = msg; +} + +unsigned int acquisitionManagerInit(void) +{ + unsigned int i; + printf("[acquisitionManager]Synchronization initialization in progress...\n"); + fflush( stdout ); + if (createSynchronizationObjects() == ERROR_INIT) + return ERROR_INIT; + + printf("[acquisitionManager]Synchronization initialization done.\n"); + + for (i = 0; i < PRODUCER_COUNT; i++) + { + pthread_create(&producers[i], NULL, &produce, &i); + } + + return ERROR_SUCCESS; +} + +void acquisitionManagerJoin(void) +{ + unsigned int i; + for (i = 0; i < PRODUCER_COUNT; i++) + { + pthread_join(producers[i], NULL); + } + + //TODO + printf("[acquisitionManager]Semaphore cleaned\n"); +} + +void *produce(void *ithread) +{ + D(printf("[acquisitionManager]Producer created with id %d\n", gettid())); + unsigned int i = 0; + MSG_BLOCK msg; + char done = 0; + while (i < PRODUCER_LOOP_LIMIT) + { + i++; + sleep(PRODUCER_SLEEP_TIME+(rand() % 5)); + + // Acquire input + getInput(*(int *)ithread, &msg); + + // Store in ring buffer + pthread_mutex_lock(&m1); + while (!done) { + pthread_mutex_lock(&m1); + if (buf_head < 100) { + buffer[buf_head] = msg; + buf_head++; + done = 1; + } + pthread_mutex_unlock(&m1); + } + pthread_mutex_unlock(&m1); + + } + printf("[acquisitionManager] %ld termination\n", gettid()); + pthread_exit(NULL); +} diff --git a/T2/tp/debug.h b/T2/tp/debug.h new file mode 100755 index 0000000..10af5ee --- /dev/null +++ b/T2/tp/debug.h @@ -0,0 +1,6 @@ +//C macro to active debug printf +#ifdef DEBUG +# define D(x) x +#else +# define D(x) +#endif \ No newline at end of file diff --git a/T2/tp/display.c b/T2/tp/display.c new file mode 100755 index 0000000..5619b72 --- /dev/null +++ b/T2/tp/display.c @@ -0,0 +1,14 @@ +#include "iDisplay.h" +#include +#include +#include "debug.h" + +void messageDisplay(volatile MSG_BLOCK* mBlock){ + unsigned int i; + messageCheck(mBlock); + printf("Message\n"); + D(printf("[")); + for(i=0;i < DATA_SIZE;i++) + D(printf("%u ",mBlock->mData[i])); + D(printf("]\n")); +} \ No newline at end of file diff --git a/T2/tp/displayManager.c b/T2/tp/displayManager.c new file mode 100755 index 0000000..bb843e6 --- /dev/null +++ b/T2/tp/displayManager.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include "displayManager.h" +#include "iDisplay.h" +#include "iAcquisitionManager.h" +#include "iMessageAdder.h" +#include "msg.h" +#include "mySoftware.h" +#include "debug.h" + +// DisplayManager thread. +pthread_t displayThread; + +/** + * Display manager entry point. + */ +static void *display( void *parameters ); + + +void displayManagerInit(void){ + pthread_create(&displayThread, NULL, display, NULL); +} + +void displayManagerJoin(void){ + pthread_join(displayThread, NULL); +} + +static void *display( void *parameters ) +{ + D(printf("[displayManager] Thread created for display with id %d\n", gettid())); + unsigned int diffCount = 0; + while(diffCount < DISPLAY_LOOP_LIMIT){ + sleep(DISPLAY_SLEEP_TIME); + // TODO + } + printf("[displayManager] %ld termination\n", gettid()); + pthread_exit(NULL); +} diff --git a/T2/tp/displayManager.h b/T2/tp/displayManager.h new file mode 100755 index 0000000..76e031e --- /dev/null +++ b/T2/tp/displayManager.h @@ -0,0 +1,14 @@ +#ifndef MESSAGE_DISPLAY_H +#define MESSAGE_DISPLAY_H + +/** +* Initializes display manager +*/ +void displayManagerInit(void); + +/** +* Waits that display manager terminates +*/ +void displayManagerJoin(void); + +#endif \ No newline at end of file diff --git a/T2/tp/iAcquisitionManager.h b/T2/tp/iAcquisitionManager.h new file mode 100755 index 0000000..040491e --- /dev/null +++ b/T2/tp/iAcquisitionManager.h @@ -0,0 +1,8 @@ +#ifndef I_ACQUISITION_MANAGER_H +#define I_ACQUISITION_MANAGER_H + +#include "msg.h" + +//TODO create accessors prototype here. + +#endif \ No newline at end of file diff --git a/T2/tp/iDisplay.h b/T2/tp/iDisplay.h new file mode 100755 index 0000000..b3b65a7 --- /dev/null +++ b/T2/tp/iDisplay.h @@ -0,0 +1,12 @@ +#ifndef I_DISPLAY_H +#define I_DISPLAY_H + +#include "msg.h" + +/** +* Displays the message content +* @param mBlock the message pointer +*/ +void messageDisplay(volatile MSG_BLOCK* mBlock); + +#endif \ No newline at end of file diff --git a/T2/tp/iMessageAdder.h b/T2/tp/iMessageAdder.h new file mode 100755 index 0000000..3958b91 --- /dev/null +++ b/T2/tp/iMessageAdder.h @@ -0,0 +1,9 @@ +#ifndef I_MESSAGE_ADDER_H +#define I_MESSAGE_ADDER_H + +#include "msg.h" + + +//TODO create accessors prototype here. + +#endif \ No newline at end of file diff --git a/T2/tp/iSensor.h b/T2/tp/iSensor.h new file mode 100755 index 0000000..eda4eec --- /dev/null +++ b/T2/tp/iSensor.h @@ -0,0 +1,13 @@ +#ifndef I_SENSOR_H +#define I_SENSOR_H + +#include "msg.h" + +/** +* Gets the input message. +* @param input the input number +* @param mBlock the message pointer returned +*/ +void getInput(const unsigned int input, volatile MSG_BLOCK* mBlock); + +#endif diff --git a/T2/tp/messageAdder.c b/T2/tp/messageAdder.c new file mode 100755 index 0000000..5edaaf8 --- /dev/null +++ b/T2/tp/messageAdder.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include "messageAdder.h" +#include "msg.h" +#include "iMessageAdder.h" +#include "mySoftware.h" +#include "iAcquisitionManager.h" +#include "debug.h" + +//consumer thread +pthread_t consumer; +//Message computed +volatile MSG_BLOCK out; +//Consumer count storage +volatile unsigned int consumeCount = 0; + +/** + * Increments the consume count. + */ +static void incrementConsumeCount(void); + +/** + * Consumer entry point. + */ +static void *sum( void *parameters ); + +//TODO create accessors to limit semaphore and mutex usage outside of this C module. + +void messageAdderInit(void){ + out.checksum = 0; + for (size_t i = 0; i < DATA_SIZE; i++) + { + out.mData[i] = 0; + pthread_create(&consumer, NULL, sum, NULL); + } +} + +void messageAdderJoin(void){ + pthread_join(consumer, NULL); +} + +static void *sum( void *parameters ) +{ + D(printf("[messageAdder] Thread created for sum with id %ld\n", gettid())); + unsigned int i = 0; + while(i +#include +#include "msg.h" +#include "debug.h" +#include + + +/** +* Add to the src message the content of add message +* @param src the message pointer +* @param add the message to add +*/ +void messageAdd(volatile MSG_BLOCK* src, volatile MSG_BLOCK* add){ + unsigned int i; + src->checksum = 0; + for(i=0;i < DATA_SIZE;i++){ + src->mData[i] += add->mData[i]; + src->checksum ^= src->mData[i]; + } + D(printf("[msg]....Sum done...\n")); +} + +/** +* Display the message content +* @param mBlock the message pointer +*/ +unsigned int messageCheck(volatile MSG_BLOCK* mBlock){ + unsigned int i, tcheck=0; + for(i=0;i < DATA_SIZE;i++) + tcheck ^= mBlock->mData[i]; + if(tcheck == mBlock->checksum){ + printf("[OK ] Checksum validated\n"); + return 1; + }else{ + printf("[ FAILED] Checksum failed, message corrupted\n"); + return 0; + } +} + +long gettid(void){ + return syscall(SYS_gettid); +} diff --git a/T2/tp/msg.h b/T2/tp/msg.h new file mode 100755 index 0000000..e141290 --- /dev/null +++ b/T2/tp/msg.h @@ -0,0 +1,31 @@ +#ifndef MSG_H +#define MSG_H + +//Message data size +#define DATA_SIZE 256 + +//message type definition +typedef struct MSG_BLOCK_TAG +{ + unsigned int checksum; + unsigned int mData[DATA_SIZE]; +} MSG_BLOCK; + +/** +* Displays the message content +* @param mBlock the message pointer +* @return 1 if the checksum is ok, 0 otherwise +*/ +unsigned int messageCheck(volatile MSG_BLOCK* mBlock); + +/** +* Adds to the src message the content of add message +* @param src the message pointer +* @param add the message to add +*/ +void messageAdd(volatile MSG_BLOCK* src, volatile MSG_BLOCK* add); + + +long gettid(void); + +#endif diff --git a/T2/tp/mySoftware.c b/T2/tp/mySoftware.c new file mode 100755 index 0000000..425e463 --- /dev/null +++ b/T2/tp/mySoftware.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +#include +#include "mySoftware.h" +#include "acquisitionManager.h" +#include "displayManager.h" +#include "messageAdder.h" +#include "displayManager.h" +#include "debug.h" + + +//The entry point of the process +int main( void ) +{ + printf("[mySoftware]Software initialization in progress...\n"); + acquisitionManagerInit(); + messageAdderInit(); + displayManagerInit(); + printf("[mySoftware]Task initialization done.\n"); + + printf("[mySoftware]Scheduling in progress...\n"); + + displayManagerJoin(); + messageAdderJoin(); + acquisitionManagerJoin(); + + printf("[mySoftware]Threads terminated\n"); + + exit(EXIT_SUCCESS); + +} diff --git a/T2/tp/mySoftware.h b/T2/tp/mySoftware.h new file mode 100755 index 0000000..fdcaf72 --- /dev/null +++ b/T2/tp/mySoftware.h @@ -0,0 +1,24 @@ +#ifndef MY_SOFTWARE_H +#define MY_SOFTWARE_H + +#include "msg.h" + +//The application return code +#define ERROR_INIT 1 +#define ERROR_SUCCESS 0 +//The number of producers +#define PRODUCER_COUNT 4 +//The number of second the producer shall sleep +#define PRODUCER_SLEEP_TIME 1 +//The number producer iterations +#define PRODUCER_LOOP_LIMIT 2 +//The number of second the display shall sleep +#define DISPLAY_SLEEP_TIME 3 +//The number display iterations +#define DISPLAY_LOOP_LIMIT 2 +//The number of second the adder shall sleep +#define ADDER_SLEEP_TIME 2 +//The number adder iterations +#define ADDER_LOOP_LIMIT PRODUCER_LOOP_LIMIT * PRODUCER_COUNT * PRODUCER_SLEEP_TIME + +#endif \ No newline at end of file diff --git a/T2/tp/preambule.c b/T2/tp/preambule.c new file mode 100755 index 0000000..bad1276 --- /dev/null +++ b/T2/tp/preambule.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +#define ERROR_INIT 1 +#define ERROR_SUCCESS 0 +#define SEMAPHORE_INITIAL_VALUE 0 +#define SEM_NAME "/preambule_sem" + +pthread_t thread_1; +sem_t *semaphore; + +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +void *produce(void *params) +{ + printf("Trying to own the mutex\n"); + pthread_mutex_lock(&mutex); + printf("Owns the mutex\n"); + pthread_mutex_unlock(&mutex); + printf("Mutex released\n"); + sem_post(semaphore); + printf("Semaphore posted\n"); + printf("Trying to gets the semaphore\n"); + sem_wait(semaphore); + printf("Semaphore taken\n"); + printf("Thread ended\n"); + pthread_exit(NULL); +} + +int main() +{ + + sem_unlink(SEM_NAME); + semaphore = sem_open(SEM_NAME, O_CREAT, 0644, SEMAPHORE_INITIAL_VALUE); + if (semaphore == SEM_FAILED) + { + perror("[sem_open"); + return ERROR_INIT; + } + printf("Creating the thread\n"); + pthread_create(&thread_1, NULL, produce, NULL); + + printf("Waiting the thread end\n"); + pthread_join(thread_1, NULL); + printf("Deleting the semaphore\n"); + sem_destroy(semaphore); + printf("Process ended\n"); + return ERROR_SUCCESS; +} \ No newline at end of file diff --git a/T2/tp/sensorManager.c b/T2/tp/sensorManager.c new file mode 100755 index 0000000..5d5f505 --- /dev/null +++ b/T2/tp/sensorManager.c @@ -0,0 +1,17 @@ +#include "iSensor.h" +#include +#include +#include "debug.h" + + +void getInput(const unsigned int input, volatile MSG_BLOCK* mBlock){ + unsigned int i; + unsigned int j = input; + D(printf("Get message for input %u \n",j)); + mBlock->checksum = 0; + for(i=0;i < DATA_SIZE;i++){ + mBlock->mData[i] = rand(); + mBlock->checksum ^= mBlock->mData[i]; + } + return; +} \ No newline at end of file