mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-12 06:11:37 +00:00
275 lines
6.5 KiB
C
275 lines
6.5 KiB
C
/********************************************************
|
|
* An example source module to accompany...
|
|
*
|
|
* "Using POSIX Threads: Programming with Pthreads"
|
|
* by Brad nichols, Dick Buttlar, Jackie Farrell
|
|
* O'Reilly & Associates, Inc.
|
|
*
|
|
********************************************************
|
|
* cancel.c --
|
|
*
|
|
* Demonstrates pthread cancellation.
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#define NUM_THREADS 3
|
|
#define MESSAGE_MAX_LEN 80
|
|
|
|
int count=NUM_THREADS; /* number of threads active */
|
|
pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER; /* mutual exclusion
|
|
for count */
|
|
pthread_cond_t init_done=PTHREAD_COND_INITIALIZER; /* signaled by
|
|
each thread after
|
|
completing initial-
|
|
ization */
|
|
int id_arg[3] = {0,1,2};
|
|
|
|
/*
|
|
* Cleanup routine: last_breath()
|
|
*/
|
|
void last_breath(char *messagep)
|
|
{
|
|
printf("\n\n%s last_breath() cleanup routine: free'ing %p\n\n",
|
|
messagep, messagep);
|
|
|
|
free(messagep);
|
|
}
|
|
|
|
/*
|
|
* print_count()
|
|
*/
|
|
void print_count(char *messagep, int id, int i)
|
|
{
|
|
int last_type,tmp_type;
|
|
|
|
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_type);
|
|
switch(id) {
|
|
case 0:
|
|
printf("%s %4d\n", messagep, i);
|
|
break;
|
|
case 1:
|
|
printf("%s \t%4d\n", messagep, i);
|
|
break;
|
|
case 2:
|
|
printf("%s \t\t%4d\n", messagep, i);
|
|
break;
|
|
}
|
|
pthread_setcanceltype(last_type, &tmp_type);
|
|
}
|
|
|
|
/*
|
|
* bullet_proof()
|
|
*/
|
|
void *bullet_proof(void *id_p)
|
|
{
|
|
int i=0, last_state;
|
|
int *my_id = id_p;
|
|
char *messagep;
|
|
|
|
|
|
messagep = (char *)malloc(MESSAGE_MAX_LEN);
|
|
sprintf(messagep, "Bullet Proof, thread #%d: ", *my_id);
|
|
|
|
printf("%s\tI'm Alive, setting general cancellation OFF\n",
|
|
messagep);
|
|
|
|
/* push last_breath() routine onto stack */
|
|
pthread_cleanup_push( (void *)last_breath, (void *)messagep );
|
|
|
|
/* We turn off general cancelability here ... */
|
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &last_state);
|
|
|
|
pthread_mutex_lock(&lock);
|
|
{
|
|
printf("\n%s signaling main that my init is done\n", messagep);
|
|
count -= 1;
|
|
/* signal to program that entering loop */
|
|
pthread_cond_signal(&init_done);
|
|
pthread_mutex_unlock(&lock);
|
|
}
|
|
|
|
/* loop forever until picked off with a cancel */
|
|
for(i = 0; i < 10000000; i++) {
|
|
if (i%10000 == 0)
|
|
print_count(messagep, *my_id, i);
|
|
if (i%100000 == 0) {
|
|
printf("\n%s This is the thread that never ends... #%d\n",
|
|
messagep, i);
|
|
}
|
|
}
|
|
|
|
/* Never get this far */
|
|
|
|
/* This pop is required by the standard, every push must have a pop
|
|
in the same lexical block. */
|
|
pthread_cleanup_pop(0);
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
/*
|
|
* ask_for_it()
|
|
*/
|
|
void *ask_for_it(void *id_p)
|
|
{
|
|
int i=0, last_state, last_type;
|
|
int *my_id = id_p;
|
|
char *messagep;
|
|
|
|
|
|
messagep = (char *)malloc(MESSAGE_MAX_LEN);
|
|
sprintf(messagep, "Ask For It, thread #%d: ", *my_id);
|
|
|
|
/* push last_breath() routine onto stack */
|
|
pthread_cleanup_push( (void *)last_breath, (void *)messagep);
|
|
|
|
/* We can turn on general cancelability here. Disable async cancellation */
|
|
printf("%s\tI'm Alive, setting deferred cancellation ON\n",
|
|
messagep);
|
|
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_type);
|
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_state);
|
|
|
|
pthread_mutex_lock(&lock);
|
|
{
|
|
printf("\n%s signaling main that my init is done\n", messagep);
|
|
count -= 1;
|
|
/* signal to program that entering loop */
|
|
pthread_cond_signal(&init_done);
|
|
pthread_mutex_unlock(&lock);
|
|
}
|
|
|
|
/* loop forever until picked off with a cancel */
|
|
for(;;i++) {
|
|
if (i%10000 == 0)
|
|
print_count(messagep, *my_id, i);
|
|
if (i%100000 == 0) {
|
|
printf("\n%s\t%d Look, I'll tell you when you can cancel me.\n",
|
|
messagep, i);
|
|
}
|
|
pthread_testcancel();
|
|
}
|
|
|
|
/* never get this far */
|
|
|
|
/* This pop is required by the standard, every push must have a pop
|
|
in the same lexical block. */
|
|
pthread_cleanup_pop(0);
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
/*
|
|
* sitting_duck()
|
|
*/
|
|
void *sitting_duck(void *id_p)
|
|
{
|
|
int i=0, last_state, last_type, last_tmp;
|
|
int *my_id = id_p;
|
|
char *messagep;
|
|
|
|
|
|
messagep = (char *)malloc(MESSAGE_MAX_LEN);
|
|
sprintf(messagep, "Sitting Duck, thread #%d: ", *my_id);
|
|
|
|
/* push last_breath() routine onto stack */
|
|
pthread_cleanup_push( (void *)last_breath, (void *)messagep);
|
|
|
|
pthread_mutex_lock(&lock);
|
|
{
|
|
printf("\n%s signaling main that my init is done\n", messagep);
|
|
count -= 1;
|
|
/* signal to program that entering loop */
|
|
pthread_cond_signal(&init_done);
|
|
pthread_mutex_unlock(&lock);
|
|
}
|
|
|
|
/* Now, we're safe to turn on async cancellability */
|
|
printf("%s\tI'm Alive, setting async cancellation ON\n",
|
|
messagep);
|
|
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &last_type);
|
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_state);
|
|
|
|
/* loop forever until picked off with a cancel */
|
|
for(;;i++) {
|
|
if (i%1000 == 0)
|
|
print_count(messagep, *my_id, i++);
|
|
if (i%10000 == 0) {
|
|
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_tmp);
|
|
printf("\n%s\tHum, nobody here but us chickens. %d\n", messagep,i);
|
|
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &last_tmp);
|
|
}
|
|
}
|
|
|
|
/* never get this far */
|
|
|
|
/* This pop is required by the standard, every push must have a pop
|
|
in the same lexical block. */
|
|
pthread_cleanup_pop(0);
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
extern int
|
|
main(void)
|
|
{
|
|
int i;
|
|
void *statusp;
|
|
pthread_t threads[NUM_THREADS];
|
|
|
|
|
|
/* spawn the threads */
|
|
pthread_create(&(threads[0]),
|
|
NULL,
|
|
ask_for_it,
|
|
(void *) &(id_arg[0]));
|
|
|
|
pthread_create(&(threads[1]),
|
|
NULL,
|
|
sitting_duck,
|
|
(void *) &(id_arg[1]));
|
|
|
|
pthread_create(&(threads[2]),
|
|
NULL,
|
|
bullet_proof,
|
|
(void *) &(id_arg[2]));
|
|
|
|
printf("main(): %d threads created\n", NUM_THREADS);
|
|
|
|
pthread_mutex_lock(&lock);
|
|
|
|
/* wait until all threads have entered loops */
|
|
while (count != 0) {
|
|
pthread_cond_wait(&init_done, &lock);
|
|
}
|
|
|
|
pthread_mutex_unlock(&lock);
|
|
|
|
printf("main(): all threads have signaled that ready\n");
|
|
|
|
/* cancel each thread */
|
|
for (i=0; i<NUM_THREADS; i++) {
|
|
pthread_cancel(threads[i]);
|
|
}
|
|
|
|
/* wait until all threads have finished */
|
|
for (i=0; i<NUM_THREADS; i++) {
|
|
pthread_join(threads[i], &statusp);
|
|
if (statusp == PTHREAD_CANCELED) {
|
|
printf("main(): joined to thread %d, statusp=PTHREAD_CANCELED\n",i);
|
|
} else {
|
|
printf("main(): joined to thread %d\n",i);
|
|
}
|
|
}
|
|
|
|
printf("main()\t\tall %d threads have finished. \n", NUM_THREADS);
|
|
|
|
return 0;
|
|
}
|