feat: add script to fetch tests
This commit is contained in:
parent
a5964068b0
commit
22ca321fae
10
fetch_tests.sh
Executable file
10
fetch_tests.sh
Executable 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
28
tst/01-main.c
Normal 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
62
tst/02-switch.c
Normal 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
66
tst/03-equity.c
Normal 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
49
tst/11-join.c
Normal 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
48
tst/12-join-main.c
Normal 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
52
tst/21-create-many.c
Normal 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;
|
||||
}
|
54
tst/22-create-many-recursive.c
Normal file
54
tst/22-create-many-recursive.c
Normal 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
71
tst/23-create-many-once.c
Normal 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
73
tst/31-switch-many.c
Normal 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
64
tst/32-switch-many-join.c
Normal 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;
|
||||
}
|
74
tst/33-switch-many-cascade.c
Normal file
74
tst/33-switch-many-cascade.c
Normal 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
88
tst/51-fibonacci.c
Normal 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
104
tst/61-mutex.c
Normal 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
122
tst/62-mutex.c
Normal 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
110
tst/71-preemption.c
Normal 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
57
tst/81-deadlock.c
Normal 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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user