feat: add script to fetch tests

This commit is contained in:
Nemo D'ACREMONT 2025-03-14 17:34:37 +01:00
parent a5964068b0
commit 22ca321fae
No known key found for this signature in database
GPG Key ID: 85F245EC3BB1E022
17 changed files with 1132 additions and 0 deletions

10
fetch_tests.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
tst_dir=tst
filenames="01-main 02-switch 03-equity 11-join 12-join-main 21-create-many 22-create-many-recursive 23-create-many-once 31-switch-many 32-switch-many-join 33-switch-many-cascade 51-fibonacci 61-mutex 62-mutex 71-preemption 81-deadlock"
mkdir -p "${tst_dir}"
for filename in ${filenames}
do
curl -o "${tst_dir}/${filename}.c" "https://goglin.gitlabpages.inria.fr/enseirb-it202/tests/${filename}.c" &
done

28
tst/01-main.c Normal file
View File

@ -0,0 +1,28 @@
#include <stdio.h>
#include <assert.h>
#include "thread.h"
/* test du thread_self et yield du main seul.
*
* le programme doit retourner correctement.
* valgrind doit être content.
*
* support nécessaire:
* - thread_yield() depuis et vers le main
* - thread_self() depuis le main
*/
int main()
{
int err, i;
for(i=0; i<10; i++) {
printf("le main yield tout seul\n");
err = thread_yield();
assert(!err);
}
printf("le main est %p\n", (void*) thread_self());
return 0;
}

62
tst/02-switch.c Normal file
View File

@ -0,0 +1,62 @@
#include <stdio.h>
#include <assert.h>
#include "thread.h"
/* test de switchs.
*
* les affichages doivent être dans le bon ordre (fifo)
* le programme doit retourner correctement.
* valgrind doit être content.
*
* support nécessaire:
* - thread_create()
* - thread_yield() depuis ou vers le main
* - thread_exit()
* - thread_join() avec récupération de la valeur de retour, ou sans
*/
static void * thfunc(void *id)
{
int err, i;
for(i=0; i<10; i++) {
printf("%s yield vers un autre thread\n", (char*) id);
err = thread_yield();
assert(!err);
}
printf("%s terminé\n", (char*) id);
thread_exit(NULL);
return (void*) 0xdeadbeef; /* unreachable, shut up the compiler */
}
int main()
{
thread_t th1,th2,th3;
void *res;
int err, i;
err = thread_create(&th1, thfunc, "fils1");
assert(!err);
err = thread_create(&th2, thfunc, "fils2");
assert(!err);
err = thread_create(&th3, thfunc, "fils3");
assert(!err);
/* des switchs avec l'autre thread */
for(i=0; i<20; i++) {
printf("le main yield vers un fils\n");
err = thread_yield();
assert(!err);
}
err = thread_join(th3, &res);
assert(!err);
assert(res == NULL);
err = thread_join(th2, NULL); /* on ignore ce code de retour */
assert(!err);
err = thread_join(th1, &res);
assert(!err);
assert(res == NULL);
printf("main terminé\n");
return 0;
}

66
tst/03-equity.c Normal file
View File

@ -0,0 +1,66 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "thread.h"
/* test de l'équité de la cooperation via des thread_yield().
*
* plus le score est proche de 1, plus
* l'ordonnancement cooperatif est equitable.
*
* support nécessaire:
* - thread_create()
* - thread_yield() depuis ou vers le main
* - retour sans thread_exit()
* - thread_join()
*/
static unsigned v[3];
static int fini = 0;
static double score = 0;
static void * thfunc(void *arg)
{
unsigned long myid = (unsigned long) arg;
int err, i;
for(i=0; i<1000 && !fini; i++) {
err = thread_yield();
assert(!err);
v[myid]++;
if (v[myid] == 1000 && !fini) {
fini = 1;
printf("le thread %lu a terminé\n", myid);
printf("nombres de yield: %u %u %u\n", v[0], v[1], v[2]);
score = (v[0]+v[1]+v[2]) / 3000.;
printf("score: %lf\n", score);
}
}
return NULL;
}
int main()
{
thread_t th1, th2;
int err;
v[0] = v[1] = v[2] = 0;
err = thread_create(&th1, thfunc, (void*)0UL);
assert(!err);
err = thread_create(&th2, thfunc, (void*)1UL);
assert(!err);
thfunc((void*)2UL);
err = thread_join(th2, NULL);
assert(!err);
err = thread_join(th1, NULL);
assert(!err);
if ( score < .8) {
return EXIT_FAILURE;
}
else {
return EXIT_SUCCESS;
}
}

49
tst/11-join.c Normal file
View File

@ -0,0 +1,49 @@
#include <stdio.h>
#include <assert.h>
#include "thread.h"
/* test du join, avec ou sans thread_exit.
*
* le programme doit retourner correctement.
* valgrind doit être content.
*
* support nécessaire:
* - thread_create()
* - thread_exit()
* - retour sans thread_exit()
* - thread_join() avec récupération valeur de retour, avec et sans thread_exit()
*/
static void * thfunc(void *dummy __attribute__((unused)))
{
thread_exit((void*)0xdeadbeef);
return NULL; /* unreachable, shut up the compiler */
}
static void * thfunc2(void *dummy __attribute__((unused)))
{
return (void*) 0xbeefdead;
}
int main()
{
thread_t th, th2;
int err;
void *res = NULL;
err = thread_create(&th, thfunc, NULL);
assert(!err);
err = thread_create(&th2, thfunc2, NULL);
assert(!err);
err = thread_join(th, &res);
assert(!err);
assert(res == (void*) 0xdeadbeef);
err = thread_join(th2, &res);
assert(!err);
assert(res == (void*) 0xbeefdead);
printf("join OK\n");
return 0;
}

48
tst/12-join-main.c Normal file
View File

@ -0,0 +1,48 @@
#include <stdio.h>
#include <assert.h>
#include "thread.h"
/* test du join du main par un fils.
*
* le programme doit terminer correctement (faire le printf et s'arreter entièrement).
* valgrind doit être content.
*
* support nécessaire:
* - thread_create()
* - thread_self() dans le main
* - thread_exit() dans le main
* - retour sans thread_exit()
* - thread_join() du main par un autre thread
*/
#ifdef USE_PTHREAD
thread_t thmain = 0;
#else
thread_t thmain = NULL; /* si votre thread_t est un pointeur */
#endif
static void * thfunc(void *dummy __attribute__((unused)))
{
void *res;
int err;
err = thread_join(thmain, &res);
assert(!err);
assert(res == (void*) 0xdeadbeef);
printf("main terminé OK\n");
return NULL;
}
int main()
{
thread_t th;
int err;
thmain = thread_self();
err = thread_create(&th, thfunc, NULL);
assert(!err);
thread_exit((void*) 0xdeadbeef);
return 0; /* unreachable, shut up the compiler */
}

52
tst/21-create-many.c Normal file
View File

@ -0,0 +1,52 @@
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/time.h>
#include "thread.h"
/* test de plein de create-destroy consécutifs.
*
* valgrind doit etre content.
* la durée du programme doit etre proportionnelle au nombre de threads donnés en argument.
* jusqu'à combien de threads cela fonctionne-t-il ?
*
* support nécessaire:
* - thread_create()
* - thread_exit()
* - thread_join() avec récupération de la valeur de retour
*/
static void * thfunc(void *dummy __attribute__((unused)))
{
thread_exit(NULL);
return (void*) 0xdeadbeef; /* unreachable, shut up the compiler */
}
int main(int argc, char *argv[])
{
thread_t th;
struct timeval tv1, tv2;
unsigned long us;
int err, i, nb;
void *res;
if (argc < 2) {
printf("argument manquant: nombre de threads\n");
return -1;
}
nb = atoi(argv[1]);
gettimeofday(&tv1, NULL);
for(i=0; i<nb; i++) {
err = thread_create(&th, thfunc, NULL);
assert(!err);
err = thread_join(th, &res);
assert(!err);
assert(res == NULL);
}
gettimeofday(&tv2, NULL);
us = (tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec);
printf("%d threads créés et détruits séquentiellement en %lu us\n", nb, us);
return 0;
}

View File

@ -0,0 +1,54 @@
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/time.h>
#include "thread.h"
/* test de plein de create-destroy récursif.
*
* valgrind doit etre content.
* la durée du programme doit etre proportionnelle au nombre de threads donnés en argument.
* jusqu'à combien de threads cela fonctionne-t-il ?
*
* support nécessaire:
* - thread_create()
* - retour sans thread_exit()
* - thread_join() avec récupération de la valeur de retour
*/
static void * thfunc(void *_nb)
{
unsigned long nb = (unsigned long) _nb;
if ((unsigned long) nb > 0) {
thread_t th;
int err;
void *res;
err = thread_create(&th, thfunc, ((char*)_nb)-1);
assert(!err);
err = thread_join(th, &res);
assert(!err);
assert(res == ((char*)_nb-1));
}
return _nb;
}
int main(int argc, char *argv[])
{
unsigned long nb;
struct timeval tv1, tv2;
unsigned long us;
if (argc < 2) {
printf("argument manquant: nombre de threads\n");
return -1;
}
nb = atoi(argv[1]);
gettimeofday(&tv1, NULL);
thfunc((void*) nb);
gettimeofday(&tv2, NULL);
us = (tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec);
printf("%ld threads créés et détruits récursivement en %lu us\n", nb, us);
return 0;
}

71
tst/23-create-many-once.c Normal file
View File

@ -0,0 +1,71 @@
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/time.h>
#include "thread.h"
/* test de plein de create, puis plein de join quand ils ont tous fini
*
* valgrind doit etre content.
* la durée du programme doit etre proportionnelle au nombre de threads donnés en argument.
* jusqu'à combien de threads cela fonctionne-t-il ?
*
* support nécessaire:
* - thread_create()
* - thread_exit()
* - thread_join() sans récupération de la valeur de retour
*/
static void * thfunc(void *dummy __attribute__((unused)))
{
thread_exit(NULL);
return (void*) 0xdeadbeef; /* unreachable, shut up the compiler */
}
int main(int argc, char *argv[])
{
thread_t *th;
int err, i, nb;
struct timeval tv1, tv2;
unsigned long us;
if (argc < 2) {
printf("argument manquant: nombre de threads\n");
return -1;
}
nb = atoi(argv[1]);
th = malloc(nb*sizeof(*th));
if (!th) {
perror("malloc");
return -1;
}
gettimeofday(&tv1, NULL);
/* on cree tous les threads */
for(i=0; i<nb; i++) {
err = thread_create(&th[i], thfunc, NULL);
assert(!err);
}
/* on leur passe la main, ils vont tous terminer */
for(i=0; i<nb; i++) {
thread_yield();
}
/* on les joine tous, maintenant qu'ils sont tous morts */
for(i=0; i<nb; i++) {
err = thread_join(th[i], NULL);
assert(!err);
}
gettimeofday(&tv2, NULL);
us = (tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec);
free(th);
printf("%d threads créés et détruits tous d'un coup en %lu us\n", nb, us);
return 0;
}

73
tst/31-switch-many.c Normal file
View File

@ -0,0 +1,73 @@
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/time.h>
#include <stdint.h>
#include "thread.h"
/* test de plein de switch par plein de threads
*
* la durée du programme doit etre proportionnelle au nombre de threads et de yields donnés en argument
*
* support nécessaire:
* - thread_create()
* - thread_yield() depuis ou vers le main
* - retour sans thread_exit()
* - thread_join() avec récupération de la valeur de retour
*/
static void * thfunc(void *_nbyield)
{
int nbyield = (intptr_t) _nbyield;
int i;
for(i=0; i<nbyield; i++)
thread_yield();
return NULL;
}
int main(int argc, char *argv[])
{
int nbth, i, err;
int nbyield;
thread_t *ths;
struct timeval tv1, tv2;
unsigned long us;
if (argc < 3) {
printf("arguments manquants: nombre de threads, puis nombre de yield\n");
return -1;
}
nbth = atoi(argv[1]);
nbyield = atoi(argv[2]);
ths = malloc(nbth * sizeof(thread_t));
assert(ths);
gettimeofday(&tv1, NULL);
for(i=0; i<nbth; i++) {
err = thread_create(&ths[i], thfunc, (void*) (intptr_t) nbyield);
assert(!err);
}
for(i=0; i<nbyield; i++)
thread_yield();
for(i=0; i<nbth; i++) {
void *res;
err = thread_join(ths[i], &res);
assert(!err);
assert(res == NULL);
}
gettimeofday(&tv2, NULL);
us = (tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec);
printf("%d yield avec %d threads: %ld us\n",
nbyield, nbth, us);
free(ths);
return 0;
}

64
tst/32-switch-many-join.c Normal file
View File

@ -0,0 +1,64 @@
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/time.h>
#include <stdint.h>
#include "thread.h"
/* test de plein de switch pendant que N-1 threads sont bloqués dans join
*
* La durée du programme doit etre proportionnelle au nombre de threads et de yields donnés en argument
*
* support nécessaire:
* - thread_create()
* - thread_yield() depuis ou vers le main
* - retour sans thread_exit()
* - thread_join() avec récupération de la valeur de retour
*/
static int nbyield;
static void * thfunc(void *_nbth)
{
int nbth = (intptr_t) _nbth;
if ((unsigned long) nbth > 0) {
thread_t th;
int err;
void *res;
err = thread_create(&th, thfunc, ((char*)_nbth)-1);
assert(!err);
err = thread_join(th, &res);
assert(!err);
assert(res == ((char*)_nbth)-1);
} else {
int i;
struct timeval tv1, tv2;
unsigned long us;
gettimeofday(&tv1, NULL);
for(i=0; i<nbyield; i++)
thread_yield();
gettimeofday(&tv2, NULL);
us = (tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec);
printf("%d yield avec plein de threads dans join: %ld us\n",
nbyield, us);
}
return _nbth;
}
int main(int argc, char *argv[])
{
unsigned long nbth;
if (argc < 3) {
printf("arguments manquants: nombre de threads, puis nombre de yield\n");
return -1;
}
nbth = atoi(argv[1]);
nbyield = atoi(argv[2]);
thfunc((void*) nbth);
printf("%ld threads créés et détruits\n", nbth);
return 0;
}

View File

@ -0,0 +1,74 @@
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/time.h>
#include <stdint.h>
#include "thread.h"
/* test une chaine de thread avec un nombre decroissants de switch quand on descend dans la chaine.
*
* La durée du programme doit etre proportionnelle au nombre de total de yields = ( nbyield * nbthread * (nbthread+1) / 2 ) donnés en argument
*
* support nécessaire:
* - thread_create()
* - thread_yield() depuis ou vers le main
* - retour sans thread_exit()
* - thread_join() avec récupération de la valeur de retour
*/
static int nbyield;
static int nbthread;
static void * thfunc(void *_nbth)
{
int nbth = (intptr_t) _nbth;
int i;
if ((unsigned long) nbth > 0) {
thread_t th;
int err;
void *res;
err = thread_create(&th, thfunc, ((char*)_nbth)-1);
assert(!err);
for(i=0; i<(nbyield*nbth); i++) {
thread_yield();
}
err = thread_join(th, &res);
assert(!err);
assert(res == ((char*)_nbth)-1);
}
else {
for(i=0; i<(nbyield*nbthread); i++) {
thread_yield();
}
}
return _nbth;
}
int main(int argc, char *argv[])
{
struct timeval tv1, tv2;
unsigned long us;
unsigned long nbth;
if (argc < 3) {
printf("arguments manquants: nombre de threads, puis nombre de yield\n");
return -1;
}
nbthread = atoi(argv[1]);
nbth = nbthread;
nbyield = atoi(argv[2]);
gettimeofday(&tv1, NULL);
thfunc((void*) nbth);
gettimeofday(&tv2, NULL);
us = (tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec);
printf("%d yield avec plein de threads dans join: %ld us\n", nbyield, us);
printf("%ld threads créés et détruits\n", nbth);
return 0;
}

88
tst/51-fibonacci.c Normal file
View File

@ -0,0 +1,88 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/time.h>
#include "thread.h"
/* fibonacci.
*
* la durée doit être proportionnel à la valeur du résultat.
* valgrind doit être content.
* jusqu'à quelle valeur cela fonctionne-t-il ?
*
* support nécessaire:
* - thread_create()
* - thread_join() avec récupération de la valeur de retour
* - retour sans thread_exit()
*/
static void * fibo(void *_value)
{
thread_t th, th2;
int err;
void *res = NULL, *res2 = NULL;
unsigned long value = (unsigned long) _value;
/* on passe un peu la main aux autres pour eviter de faire uniquement la partie gauche de l'arbre */
thread_yield();
if (value < 3)
return (void*) 1;
err = thread_create(&th, fibo, (void*)(value-1));
assert(!err);
err = thread_create(&th2, fibo, (void*)(value-2));
assert(!err);
err = thread_join(th, &res);
assert(!err);
err = thread_join(th2, &res2);
assert(!err);
return (void*)((unsigned long) res + (unsigned long) res2);
}
unsigned long fibo_checker( unsigned long n )
{
unsigned long a = 1;
unsigned long b = 1;
unsigned long c, i;
if ( n <= 2 ) {
return 1;
}
for( i=2; i<n; i++ ) {
c = a + b;
a = b;
b = c;
}
return c;
}
int main(int argc, char *argv[])
{
unsigned long value, res;
struct timeval tv1, tv2;
double s;
if (argc < 2) {
printf("argument manquant: entier x pour lequel calculer fibonacci(x)\n");
return -1;
}
value = atoi(argv[1]);
gettimeofday(&tv1, NULL);
res = (unsigned long) fibo((void *)value);
gettimeofday(&tv2, NULL);
s = (tv2.tv_sec-tv1.tv_sec) + (tv2.tv_usec-tv1.tv_usec) * 1e-6;
if (res != fibo_checker(value)) {
printf("fibo(%lu) != %lu (FAILED)\n", value, fibo_checker(value));
return EXIT_FAILURE;
} else {
printf("fibo(%lu) = %lu en %e s\n", value, res, s );
return EXIT_SUCCESS;
}
}

104
tst/61-mutex.c Normal file
View File

@ -0,0 +1,104 @@
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/time.h>
#include "thread.h"
/* test de faire une somme avec plein de thread sur un compteur partagé
*
* valgrind doit etre content.
* Le résultat doit etre égal au nombre de threads * 1000.
* La durée du programme doit etre proportionnelle au nombre de threads donnés en argument.
*
* support nécessaire:
* - thread_create()
* - retour sans thread_exit()
* - thread_join() sans récupération de la valeur de retour
* - thread_mutex_init()
* - thread_mutex_destroy()
* - thread_mutex_lock()
* - thread_mutex_unloc()
*/
int counter = 0;
thread_mutex_t lock;
static void * thfunc(void *dummy __attribute__((unused)))
{
unsigned long i = 0;
int tmp;
for(i=0; i<1000;i++) {
/* Verrouille la section critique accédant a counter */
thread_mutex_lock(&lock);
tmp = counter;
thread_yield();
tmp++;
thread_yield();
counter = tmp;
thread_mutex_unlock(&lock);
}
return NULL;
}
int main(int argc, char *argv[])
{
thread_t *th;
int err, i, nb;
struct timeval tv1, tv2;
unsigned long us;
if (argc < 2) {
printf("argument manquant: nombre de threads\n");
return -1;
}
nb = atoi(argv[1]);
if (thread_mutex_init(&lock) != 0) {
fprintf(stderr, "thread_mutex_init failed\n");
return -1;
}
th = malloc(nb*sizeof(*th));
if (!th) {
perror("malloc");
return -1;
}
gettimeofday(&tv1, NULL);
/* on cree tous les threads */
for(i=0; i<nb; i++) {
err = thread_create(&th[i], thfunc, NULL);
assert(!err);
}
/* on leur passe la main, ils vont tous terminer */
for(i=0; i<nb; i++) {
thread_yield();
}
/* on les joine tous, maintenant qu'ils sont tous morts */
for(i=0; i<nb; i++) {
err = thread_join(th[i], NULL);
assert(!err);
}
gettimeofday(&tv2, NULL);
free(th);
thread_mutex_destroy(&lock);
us = (tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec);
if ( counter == ( nb * 1000 ) ) {
printf("La somme a été correctement calculée (%d * 1000 = %d) en %ld us\n", nb, counter, us);
return EXIT_SUCCESS;
}
else {
printf("Le résultat est INCORRECT: %d * 1000 != %d\n", nb, counter);
return EXIT_FAILURE;
}
}

122
tst/62-mutex.c Normal file
View File

@ -0,0 +1,122 @@
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>
#include <sys/time.h>
#include "thread.h"
/* test de faire une somme avec plein de thread sur un compteur partagé
*
* valgrind doit etre content.
* Les résultats doivent etre égals au nombre de threads * 1000.
* La durée du programme doit etre proportionnelle au nombre de threads donnés en argument.
*
* support nécessaire:
* - thread_create()
* - retour sans thread_exit()
* - thread_join() sans récupération de la valeur de retour
* - thread_mutex_init()
* - thread_mutex_destroy()
* - thread_mutex_lock()
* - thread_mutex_unloc()
*/
#define NB_MUTEX 10
int counter[NB_MUTEX] = { 0 };
thread_mutex_t lock[NB_MUTEX];
static void * thfunc(void *_nb)
{
unsigned long nb = (unsigned long) _nb;
unsigned long i = 0;
int tmp;
int m = nb % NB_MUTEX;
for(i=0; i<1000;i++) {
/* Verrouille la section critique accédant a counter */
thread_mutex_lock(&lock[m]);
tmp = counter[m];
thread_yield();
tmp++;
thread_yield();
counter[m] = tmp;
thread_mutex_unlock(&lock[m]);
}
return NULL;
}
int main(int argc, char *argv[])
{
thread_t *th;
int i, nbthrd;
int err, nb;
struct timeval tv1, tv2;
unsigned long us;
if (argc < 2) {
printf("argument manquant: nombre de threads\n");
return -1;
}
nb = atoi(argv[1]);
nbthrd = nb * NB_MUTEX;
for(i=0; i<NB_MUTEX; i++) {
if (thread_mutex_init(&lock[i]) != 0) {
fprintf(stderr, "thread_mutex_init(lock[%d]) failed\n", i);
return -1;
}
}
th = malloc(nbthrd*sizeof(*th));
if (!th) {
perror("malloc");
return -1;
}
gettimeofday(&tv1, NULL);
/* on cree tous les threads */
for(i=0; i<nbthrd; i++) {
err = thread_create(&th[i], thfunc, (void*)((intptr_t)i));
assert(!err);
}
/* on leur passe la main, ils vont tous terminer */
for(i=0; i<nb; i++) {
thread_yield();
}
/* on les joine tous, maintenant qu'ils sont tous morts */
for(i=0; i<nbthrd; i++) {
err = thread_join(th[i], NULL);
assert(!err);
}
gettimeofday(&tv2, NULL);
free(th);
for(i=0; i<NB_MUTEX; i++) {
thread_mutex_destroy(&lock[i]);
}
err = EXIT_SUCCESS;
for(i=0; i<NB_MUTEX; i++) {
if ( counter[i] == ( nb * 1000 ) ) {
printf("La somme %d a été correctement calculée: %d * 1000 = %d\n", i, nb, counter[i]);
}
else {
printf("Le résultat %d est INCORRECT: %d * 1000 != %d\n", i, nb, counter[i]);
err = EXIT_FAILURE;
}
}
if(err == EXIT_SUCCESS) {
us = (tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec);
printf("Programme exécuté en %ld us\n", us);
}
return err;
}

110
tst/71-preemption.c Normal file
View File

@ -0,0 +1,110 @@
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>
#include <inttypes.h>
#include <sys/time.h>
#include "thread.h"
/* test de validation de la pré-emption (et par effet de bord de certaines implémentation de priorités)
*
* valgrind doit etre content.
* La durée du programme doit etre proportionnelle au nombre de threads donnés en argument.
* L'affichage doit être une série d'id alternée dans un ordre plus ou
* moin aléatoire, et non une suite de 0, puis de 1, puis de 2, ...
*
* support nécessaire:
* - thread_create()
* - retour sans thread_exit()
* - thread_join() sans récupération de la valeur de retour
*/
#define NB_ITER 100
#define ITER_LENGTH 1000000
static int fini = 0;
static double score = 0;
static long *values = NULL;
static void * thfunc( void *arg )
{
unsigned long i, j = 0;
int me = (intptr_t)arg;
for(i=0; i<NB_ITER;i++) {
for(j=0; j<ITER_LENGTH;j++) {
if (fini) {
return NULL;
}
values[me]++;
}
fprintf(stderr, "%ld ", (intptr_t)arg );
}
fini = 1;
return NULL;
}
int main(int argc, char *argv[])
{
thread_t *th;
int i, err, nb;
struct timeval tv1, tv2;
unsigned long us;
if (argc < 2) {
printf("argument manquant: nombre de threads\n");
return -1;
}
nb = atoi(argv[1]);
th = malloc(nb * sizeof(*th));
if (!th) {
perror("malloc(th)");
return -1;
}
values = calloc( nb+1, sizeof(long) );
if (!values) {
perror("malloc(values)");
return -1;
}
gettimeofday(&tv1, NULL);
/* on cree tous les threads */
for(i=0; i<nb; i++) {
err = thread_create(&th[i], thfunc, (void*)((intptr_t)i));
assert(!err);
}
/* On participe au réchauffement climatique */
thfunc( (void*)((intptr_t)nb) );
/* on les join tous, maintenant qu'ils sont tous morts */
score = values[nb];
for(i=0; i<nb; i++) {
err = thread_join(th[i], NULL);
assert(!err);
score += values[i];
}
gettimeofday(&tv2, NULL);
us = (tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec);
score = score / ( (double)(nb+1) * NB_ITER * ITER_LENGTH );
printf("\nscore: %lf\n", score );
printf("Programme exécuté en %ld us\n", us);
free(th);
free(values);
if ( score < .5 ) {
return EXIT_FAILURE;
}
else {
printf("Temps attendu pour le programme complet: %e us\n", us / score );
return EXIT_SUCCESS;
}
}

57
tst/81-deadlock.c Normal file
View File

@ -0,0 +1,57 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include "thread.h"
/* test de detection d'un deadlock lors d'un cycle de thread qui joignent tous le suivant.
* main(th0) joine th1 qui joine th2 qui joine main.
* il faut qu'un join renvoie EDEADLK quand il detecte le deadlock, et les autres renvoient 0 normalement.
*/
static thread_t th0, th1, th2;
int totalerr = 0;
static void * thfunc2(void *dummy __attribute__((unused)))
{
void *res;
int err = thread_join(th0, &res);
printf("join th2->th0 = %d\n", err);
totalerr += err;
thread_exit(NULL);
}
static void * thfunc1(void *dummy __attribute__((unused)))
{
void *res;
int err = thread_create(&th2, thfunc2, NULL);
assert(!err);
err = thread_join(th2, &res);
printf("join th1->th2 = %d\n", err);
totalerr += err;
thread_exit(NULL);
}
int main()
{
void *res;
int err;
th0 = thread_self();
err = thread_create(&th1, thfunc1, NULL);
assert(!err);
err = thread_join(th1, &res);
printf("join th0->th1 = %d\n", err);
totalerr += err;
printf("somme des valeurs de retour = %d\n", totalerr);
assert(totalerr == EDEADLK);
if ( totalerr == EDEADLK ) {
return EXIT_SUCCESS;
}
else {
return EXIT_FAILURE;
}
}