forked from IUTInfoMontp-M2101/cours
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcours02.html
400 lines (382 loc) · 15.7 KB
/
cours02.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Cours n°2 : Appels systèmes<br>et entrée / sortie</title>
<link rel="stylesheet" href="https://vpoupet.github.io/myriad/slides/slides.css">
<link rel="stylesheet" href="https://vpoupet.github.io/myriad/slides/themes/myriad/myriad.css">
<link rel="stylesheet" href="highlight.css">
</head>
<body>
<section class="title">
<h1>Cours n°2 :<br>Appels systèmes<br>et entrée / sortie</h1>
<div class="context">M2101 - Architecture et programmation bas niveau</div>
<div class="author">Victor Poupet</div>
<time>2019-02-10</time>
</section>
<section class="single">
<h1>Système d'exploitation</h1>
<div>
<ul>
<li>Le système d'exploitation (OS) est le premier programme exécuté au démarrage de l'ordinateur</li>
<li>
C'est l'OS qui gère toute l'activité de l'ordinateur (mémoire, utilisateurs, processeur, périphériques, réseau, etc.)</li>
<li>En cours : <em>Unix</em> (mais les autres sont similaires)</li>
<li>
Les programmes communiquent avec l'OS par l'intérmédiaire d'appels systèmes (<em>system call</em>)</li>
</ul>
</div>
</section>
<section class="single">
<h1>Appels systèmes</h1>
<div>
Les appels systèmes ressemblent à des procédures (appels de fonction), avec toutefois des différences importantes :
<ul>
<li>Les appels systèmes sont très coûteux en ressources :
<ul>
<li>le système sauvegarde l'état</li>
<li>l'OS prend le contrôle du CPU</li>
<li>l'OS exécute une tâche spécifique</li>
<li>l'OS sauvegarde son état</li>
<li>le contrôle est rendu au processus qui a lancé l'appel</li>
</ul>
</li>
<li>Les appels systèmes dépendent du système d'exploitation</li>
<li>Il ne faut pas les utiliser directement si le programme doit être portable</li>
<li>
La réalisation détaillée d'un appel système demande une connaissance précise des registres du processeur</li>
<li>Il faut être très prudent pour ne pas provoquer d'erreurs</li>
<li>On utilise en général une fonction qui se charge de faire l'appel</li>
</ul>
</div>
</section>
<section class="split">
<h1>Entrée / Sortie</h1>
<div class="side">
<pre><code class="cpp">int <span class="highlight">open</span>(char *path, int flags[, int mode]);
int <span class="highlight">close</span>(int fd);
int <span class="highlight">read</span>(int fd, char *buf, int size);
int <span class="highlight">write</span>(int fd, char *buf, int size);
off_t <span class="highlight">lseek</span>(int fd, off_t offset, int whence);</code></pre>
</div>
<div class="side">
<p>Il existe 5 appels systèmes principaux pour manipuler des fichiers.</p>
<ul>
<li>
ressemblent à des procédures, mais sont envoyés directement au système souvent on utilise des fonctions qui font un appel système (ex : <code>fopen</code>
qui appelle <code>open</code>)
</li>
<li>
les entrées/sorties sont gérées par l'OS pour éviter que des erreurs dans les programmes aient des conséquences sur le système de fichiers</li>
<li>chaque appel est décrit dans sa page de manuel (ex : <code>man 2 open</code>)</li>
</ul>
</div>
</section>
<section class="single">
<h1>man 2 open</h1>
<div>
<pre><code class="plaintext">OPEN(2) BSD System Calls Manual OPEN(2)
NAME
<span class="highlight">open</span> -- open or create a file for reading or writing
SYNOPSIS
<span class="highlight">#include <fcntl.h></span>
<span class="highlight">int open(const char *path, int oflag, ...);</span>
DESCRIPTION
The file name specified by path is opened for reading and/or writing, as specified by the argument oflag; the file descriptor is returned to the calling process.
The oflag argument may indicate that the file is to be created if it does not exist (by specifying the O_CREAT flag). In this case, open requires a third argument mode_t mode; the file is created with mode mode as described in chmod(2) and modified by the process' umask value (see umask(2)).</code></pre>
</div>
</section>
<section class="split">
<h1>Open</h1>
<div class="side">
<pre><code class="cpp">int <span class="highlight">open</span>(char *path, int flags[, int mode]);</code></pre>
<hr>
<pre><code class="cpp">#include <fcntl.h>
main() {
int fd;
fd = <span class="highlight">open</span>("test.txt", O_RDONLY);
printf("%d\n", fd);
}</code></pre>
</div>
<div class="side">
<p>L'appel <code>open</code> sert à demander l'accès à un fichier</p>
<ul>
<li><code>path</code> indique le chemin du fichier</li>
<li><code>flags</code> indique comment on veut manipuler le fichier</li>
<li><code>mode</code> définit les permissions à donner en cas de création d'un nouveau fichier</li>
<li>le résultat est un entier correspondant à un descripteur de fichier (ou -1 en cas d'erreur)</li>
<li>Tous les autres appels E/S utilisent un descripteur de fichier</li>
</ul>
</div>
</section>
<section class="split">
<h1>Open (flags)</h1>
<div class="side">
<pre><code><span class="highlight">O_RDONLY</span> open for reading only
<span class="highlight">O_WRONLY</span> open for writing only
<span class="highlight">O_RDWR</span> open for reading and writing
O_NONBLOCK do not block on open or for data to become available
<span class="highlight">O_APPEND</span> append on each write
<span class="highlight">O_CREAT</span> create file if it does not exist
<span class="highlight">O_TRUNC</span> truncate size to 0
O_EXCL error if O_CREAT and the file exists
...</code></pre>
</div>
<div class="side">
<ul>
<li>L'argument <code>flags</code> est un ou bit-à-bit de valeurs</li>
<li>Les valeurs possibles sont définies dans <a href="cours02/fcntl.h"><code>/usr/include/sys/fcntl.h</code></a></li>
</ul>
</div>
</section>
<section class="split">
<h1>Close</h1>
<div class="side">
<pre><code class="cpp">int <span class="highlight">close</span>(int fd);</code></pre>
<hr>
<pre><code class="cpp">#include <fcntl.h>
#include <unistd.h>
main() {
int fd1, fd2;
fd1 = <span class="highlight">open</span>("test.txt", O_RDONLY);
if (fd1 < 0) {
exit(1);
}
fd2 = <span class="highlight">open</span>("test.txt", O_RDONLY);
if (fd2 < 0) {
exit(1);
}
if (<span class="highlight">close</span>(fd1) < 0) {
exit(1);
}
}</code></pre>
</div>
<div class="side">
<p>L'appel <code>close</code> permet de libérer un descripteur de fichier</p>
<ul>
<li>Le résultat est 0 en cas de réussite, -1 en cas d'erreur</li>
<li>Les descripteurs de fichier sont tous libérés à la fin d'un processus</li>
<li>
Le nombre de fichiers ouverts par un processus est limité (dépend du système, varie d'une centaine à plusieurs milliers)</li>
</ul>
</div>
</section>
<section class="split">
<h1>Read</h1>
<div class="side">
<pre><code class="cpp">int <span class="highlight">read</span>(int fd, char *buf, int size);</code></pre>
<hr>
<pre><code class="cpp">int main() {
char *b;
int fd, sz;
b = malloc(sizeof(char) * 11);
fd = <span class="highlight">open</span>("test.txt", O_RDONLY);
if (fd < 0) {
exit(1);
}
do {
sz = <span class="highlight">read</span>(fd, b, 10);
b[sz] = '\0';
printf("lu: %s\n", b);
} while (sz == 10);
<span class="highlight">close</span>(fd);
}</code></pre>
</div>
<div class="side">
<p>L'appel <code>read</code> sert à lire des octets dans un fichier</p>
<ul>
<li><code>fd</code> est le descripteur du fichier à lire</li>
<li><code>buf</code> est un pointeur vers un tableau où mettre les caractères lus</li>
<li><code>size</code> est le nombre d'octets à lire</li>
<li>le résultat est le nombre d'octets effectivement lus (peut être inférieur à <code>size</code> si on est en fin de fichier)</li>
</ul>
</div>
</section>
<section class="split">
<h1>Write</h1>
<div class="side">
<pre><code class="cpp">int <span class="highlight">write</span>(int fd, char *buf, int size);</code></pre>
<hr>
<pre><code class="cpp">int main() {
int fd, sz;
char *txt;
fd = <span class="highlight">open</span>("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
exit(1);
}
txt = "Bonjour\n";
sz = <span class="highlight">write</span>(fd, txt, 8);
<span class="highlight">close</span>(fd);
}</code></pre>
</div>
<div class="side">
<p>L'appel <code>write</code> permet d'écrire des octets dans un fichier</p>
<ul>
<li><code>fd</code> est le descripteur du fichier où écrire</li>
<li><code>buf</code> est un pointeur vers un tableau de caractères à écrire</li>
<li><code>size</code> correspond au nombre de caractères du tableau <code>buf</code> à écrire</li>
<li>le résultat est le nombre d'octets effectivement écrits (devrait toujours être égal à <code>size</code>)</li>
</ul>
</div>
</section>
<section class="split">
<h1>Pointeur de fichier</h1>
<div class="side">
<pre><code class="cpp">int main() {
char *c;
int fd, sz;
c = malloc(sizeof(char) * 10);
fd = open("test.txt", O_RDWR | O_APPEND);
if (fd < 0) {
exit(1);
}
while(1) {
sz = read(fd, c, 10);
write(fd, c, sz);
if (sz < 10) break;
}
close(fd);
}</code></pre>
</div>
<div class="side">
<p>Les fichiers ouverts sont tous associés à un <em>pointeur de fichier</em> qui indique un emplacement dans le fichier</p>
<ul>
<li>Initialement, le pointeur est au début du fichier</li>
<li>Lorsque l'on utilise <code>read</code> ou <code>write</code>, la lecture et l'écriture se font au niveau du pointeur</li>
<li>Le pointeur est automatiquement avancé par la lecture et l'écriture</li>
</ul>
</div>
</section>
<section class="split">
<h1>Ouvertures multiples</h1>
<div class="side">
<pre><code class="cpp only" data-end="1">int main() {
int fd1, fd2;
fd1 = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC);
fd2 = open("test.txt", O_WRONLY);
write(fd1, "un ", 3);
write(fd2, "deux ", 5);
write(fd1, "trois ", 6);
}
<span class="uncover" data-step="1">⟶ deutrois</span></code><code class="cpp only" data-start="2">int main() {
int fd1, fd2;
fd1 = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC | <span class="highlight">O_APPEND</span>);
fd2 = open("test.txt", O_WRONLY | <span class="highlight">O_APPEND</span>);
write(fd1, "un ", 3);
write(fd2, "deux ", 5);
write(fd1, "trois ", 6);
}
<span class="uncover" data-step="3">⟶ un deux trois</span></code></pre>
</div>
<div class="side">
<p>On peut ouvrir plusieurs fois un même fichier (même en écriture)</p>
<ul>
<li>chaque descripteur a son propre pointeur de fichier</li>
<li>les ouvertures en mode <code>O_APPEND</code> restent à la fin du fichier</li>
</ul>
</div>
</section>
<section class="split">
<h1>stdin, stdout, stderr</h1>
<div class="side">
<pre><code class="cpp">main() {
char c;
while (read(0, & c, 1) == 1) {
write(1, &c, 1);
}
}</code></pre>
</div>
<div class="side">
<p>Les trois premiers descripteurs de fichiers sont automatiquement attribués à chaque processus :</p>
<ul>
<li>0 : entrée standard (<code>stdin</code>)</li>
<li>1 : sortie standard (<code>stdout</code>)</li>
<li>2 : sortie d'erreur (<code>stderr</code>)</li>
</ul>
<p>On peut directement utiliser ces descripteurs de fichiers sans avoir à utiliser <code>open</code>.</p>
</div>
</section>
<section class="split">
<h1>lseek</h1>
<div class="side">
<pre><code class="cpp">int main() {
char c[10];
int fd, sz;
fd = open("test.txt", O_RDWR);
if (fd < 0) exit(1);
int rp = 0;
int wp = <span class="highlight">lseek</span>(fd, 0, SEEK_END);
do {
<span class="highlight">lseek</span>(fd, rp, SEEK_SET);
sz = read(fd, c, 10);
rp = <span class="highlight">lseek</span>(fd, 0, SEEK_CUR);
<span class="highlight">lseek</span>(fd, wp, SEEK_SET);
write(fd, c, sz);
wp = <span class="highlight">lseek</span>(fd, 0, SEEK_CUR);
} while (sz == 10);
close(fd);
}</code></pre>
</div>
<div class="side">
<p><code>lseek</code> permet de déplacer manuellement le pointeur de fichier</p>
<ul>
<li><code>fd</code> désigne le descripteur de fichier</li>
<li><code>offset</code> indique le nombre d'octets de déplacement</li>
<li><code>whence</code> permet de décrire la référence du déplacement
<ul>
<li><code>SEEK_SET</code> début du fichier</li>
<li><code>SEEK_CUR</code> position actuelle</li>
<li><code>SEEK_END</code> fin du fichier</li>
</ul>
</li>
<li>Le résultat est la position absolue du curseur après déplacement</li>
</ul>
<p>Il est possible de déplacer le curseur au-delà de la fin du fichier</p>
</div>
</section>
<section class="split">
<h1>stdio.h</h1>
<div class="side">
<pre><code class="cpp">int main() {
<span class="highlight">FILE *fpin, *fpout;</span>
int i=0;
fpin = <span class="highlight">fopen</span>("test.txt", "r");
fpout = <span class="highlight">fopen</span>("res.txt", "w");
char s[80];
while(<span class="highlight">fgets</span>(s, 80, fpin)) {
<span class="highlight">fprintf</span>(fpout, "ligne %d: %s", i, s);
i++;
}
<span class="highlight">fclose</span>(fpin);
<span class="highlight">fclose</span>(fpout);
}</code></pre>
</div>
<div class="side">
<p>
En général, on n'appelle pas directement les appels systèmes mais on utilise des fonctions de la librairie C qui les appellent indirectement :</p>
<ul>
<li><code>fopen</code>, <code>fclose</code></li>
<li><code>fgetc</code>, <code>fgets</code>, <code>fscanf</code>, etc.</li>
<li><code>fputc</code>, <code>fprintf</code>, <code>fputs</code>, etc.</li>
</ul><br>
<p>
Ces fonctions manipulent les fichiers par l'intermédiaire de pointeurs de fichiers (<em>file pointers</em>) de type <code>FILE*</code> (structure contenant un descripteur de fichier, et des informations
supplémentaires)
</p>
</div>
</section>
<script src="highlight.pack.js"></script>
<script language="Javascript">
document.addEventListener('DOMContentLoaded', (event) => {
hljs.configure({
languages: [], // disable automatic language detection
});
document.querySelectorAll('code').forEach((block) => {
hljs.highlightBlock(block);
});
});
</script>
<script src="https://vpoupet.github.io/myriad/slides/slides.js"></script>
<script src="https://vpoupet.github.io/myriad/slides/themes/myriad/myriad.js"></script>
</body>
</html>