X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=test%2Frain.c;h=471a88d61cdb6d7dbba6e05b1593ac16adee5c63;hp=3f6c39fc8f19a066e52b4e5f871c4e62b7949203;hb=ab61bfec8cb0c26638ea53ceadcd17048ee02996;hpb=88d50b5d7057d4f59c586c93ff290d0a39528f70 diff --git a/test/rain.c b/test/rain.c index 3f6c39fc..471a88d6 100644 --- a/test/rain.c +++ b/test/rain.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2006,2008 Free Software Foundation, Inc. * + * Copyright (c) 1998-2011,2012 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -26,7 +26,7 @@ * authorization. * ****************************************************************************/ /* - * $Id: rain.c,v 1.26 2008/03/09 00:17:09 tom Exp $ + * $Id: rain.c,v 1.40 2012/01/21 23:54:47 tom Exp $ */ #include @@ -38,7 +38,8 @@ WANT_USE_WINDOW(); -#define MAX_DROP 5 +#define MAX_THREADS 10 +#define MAX_DROP 5 struct DATA; @@ -47,12 +48,24 @@ typedef void (*DrawPart) (struct DATA *); typedef struct DATA { int y, x; #ifdef USE_PTHREADS - pthread_t thread; DrawPart func; int state; #endif } DATA; +#ifdef USE_PTHREADS +pthread_cond_t cond_next_drop; +pthread_mutex_t mutex_next_drop; +static int used_threads; + +typedef struct { + pthread_t myself; + long counter; +} STATS; + +static STATS drop_threads[MAX_THREADS]; +#endif + static void onsig(int n GCC_UNUSED) { @@ -61,23 +74,23 @@ onsig(int n GCC_UNUSED) ExitProgram(EXIT_FAILURE); } -static float +static double ranf(void) { long r = (rand() & 077777); - return ((float) r / 32768.); + return ((double) r / 32768.); } static int random_x(void) { - return (((float) (COLS - 4) * ranf()) + 2); + return (int) (((double) (COLS - 4) * ranf()) + 2); } static int random_y(void) { - return (((float) (LINES - 4) * ranf()) + 2); + return (int) (((double) (LINES - 4) * ranf()) + 2); } static int @@ -89,10 +102,10 @@ next_j(int j) --j; if (has_colors()) { int z = (int) (3 * ranf()); - chtype color = COLOR_PAIR(z); + chtype color = (chtype) COLOR_PAIR(z); if (z) color |= A_BOLD; - attrset(color); + (void) attrset(color); } return j; } @@ -100,59 +113,58 @@ next_j(int j) static void part1(DATA * drop) { - mvaddch(drop->y, drop->x, '.'); + MvAddCh(drop->y, drop->x, '.'); } static void part2(DATA * drop) { - mvaddch(drop->y, drop->x, 'o'); + MvAddCh(drop->y, drop->x, 'o'); } static void part3(DATA * drop) { - mvaddch(drop->y, drop->x, 'O'); + MvAddCh(drop->y, drop->x, 'O'); } static void part4(DATA * drop) { - mvaddch(drop->y - 1, drop->x, '-'); - mvaddstr(drop->y, drop->x - 1, "|.|"); - mvaddch(drop->y + 1, drop->x, '-'); + MvAddCh(drop->y - 1, drop->x, '-'); + MvAddStr(drop->y, drop->x - 1, "|.|"); + MvAddCh(drop->y + 1, drop->x, '-'); } static void part5(DATA * drop) { - mvaddch(drop->y - 2, drop->x, '-'); - mvaddstr(drop->y - 1, drop->x - 1, "/ \\"); - mvaddstr(drop->y, drop->x - 2, "| O |"); - mvaddstr(drop->y + 1, drop->x - 1, "\\ /"); - mvaddch(drop->y + 2, drop->x, '-'); + MvAddCh(drop->y - 2, drop->x, '-'); + MvAddStr(drop->y - 1, drop->x - 1, "/ \\"); + MvAddStr(drop->y, drop->x - 2, "| O |"); + MvAddStr(drop->y + 1, drop->x - 1, "\\ /"); + MvAddCh(drop->y + 2, drop->x, '-'); } static void part6(DATA * drop) { - mvaddch(drop->y - 2, drop->x, ' '); - mvaddstr(drop->y - 1, drop->x - 1, " "); - mvaddstr(drop->y, drop->x - 2, " "); - mvaddstr(drop->y + 1, drop->x - 1, " "); - mvaddch(drop->y + 2, drop->x, ' '); + MvAddCh(drop->y - 2, drop->x, ' '); + MvAddStr(drop->y - 1, drop->x - 1, " "); + MvAddStr(drop->y, drop->x - 2, " "); + MvAddStr(drop->y + 1, drop->x - 1, " "); + MvAddCh(drop->y + 2, drop->x, ' '); } #ifdef USE_PTHREADS static void napsome(void) { - refresh(); napms(60); } /* - * This runs inside the mutex. + * This runs inside the use_window() mutex. */ static int really_draw(WINDOW *win, void *arg) @@ -162,6 +174,7 @@ really_draw(WINDOW *win, void *arg) (void) win; next_j(data->state); data->func(data); + refresh(); return OK; } @@ -174,40 +187,120 @@ draw_part(void (*func) (DATA *), int state, DATA * data) napsome(); } +/* + * Tell the threads that one of them can start work on a new raindrop. + * They may all be busy if we're sending requests too rapidly. + */ +static int +put_next_drop(void) +{ + pthread_cond_signal(&cond_next_drop); + pthread_mutex_unlock(&mutex_next_drop); + + return 0; +} + +/* + * Wait until we're assigned the task of drawing a new raindrop. + */ +static int +get_next_drop(void) +{ + pthread_mutex_lock(&mutex_next_drop); + pthread_cond_wait(&cond_next_drop, &mutex_next_drop); + + return TRUE; +} + static void * draw_drop(void *arg) { DATA mydata; + int mystats; + + /* + * Find myself in the list of threads so we can count the number of loops. + */ + for (mystats = 0; mystats < MAX_THREADS; ++mystats) { +#if defined(__MINGW32__) && !defined(__WINPTHREADS_VERSION) + if (drop_threads[mystats].myself.p == pthread_self().p) +#else + if (drop_threads[mystats].myself == pthread_self()) +#endif + break; + } + + do { + if (mystats < MAX_THREADS) + drop_threads[mystats].counter++; - mydata = *(DATA *) arg; /* make a copy of caller's data */ + /* + * Make a copy of caller's data. We're cheating for the cases after + * the first loop since we still have a pointer into the main thread + * to the data which it uses for setting up this thread (but it has + * been modified to use different coordinates). + */ + mydata = *(DATA *) arg; - draw_part(part1, 0, &mydata); - draw_part(part2, 1, &mydata); - draw_part(part3, 2, &mydata); - draw_part(part4, 3, &mydata); - draw_part(part5, 4, &mydata); - draw_part(part6, 0, &mydata); + draw_part(part1, 0, &mydata); + draw_part(part2, 1, &mydata); + draw_part(part3, 2, &mydata); + draw_part(part4, 3, &mydata); + draw_part(part5, 4, &mydata); + draw_part(part6, 0, &mydata); + } while (get_next_drop()); return NULL; } + +/* + * The description of pthread_create() is misleading, since it implies that + * threads will exit cleanly after their function returns. + * + * Since they do not (and the number of threads is limited by system + * resources), make a limited number of threads, and signal any that are + * waiting when we want a thread past that limit. + */ +static int +start_drop(DATA * data) +{ + int rc; + + if (!used_threads) { + /* mutex and condition for signalling thread */ + pthread_mutex_init(&mutex_next_drop, NULL); + pthread_cond_init(&cond_next_drop, NULL); + } + + if (used_threads < MAX_THREADS) { + rc = pthread_create(&(drop_threads[used_threads].myself), + NULL, + draw_drop, + data); + ++used_threads; + } else { + rc = put_next_drop(); + } + return rc; +} #endif static int get_input(void) { - int ch; - ch = USING_WINDOW(stdscr, wgetch); - return ch; + return USING_WINDOW(stdscr, wgetch); } int main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED) { + bool done = FALSE; DATA drop; +#ifndef USE_PTHREADS DATA last[MAX_DROP]; +#endif int j = 0; - bool done = FALSE; setlocale(LC_ALL, ""); @@ -221,28 +314,29 @@ main(int argc GCC_UNUSED, if (use_default_colors() == OK) bg = -1; #endif - init_pair(1, COLOR_BLUE, bg); - init_pair(2, COLOR_CYAN, bg); + init_pair(1, COLOR_BLUE, (short) bg); + init_pair(2, COLOR_CYAN, (short) bg); } nl(); noecho(); curs_set(0); timeout(0); +#ifndef USE_PTHREADS for (j = MAX_DROP; --j >= 0;) { last[j].x = random_x(); last[j].y = random_y(); } + j = 0; +#endif while (!done) { drop.x = random_x(); drop.y = random_y(); #ifdef USE_PTHREADS - if (pthread_create(&(drop.thread), NULL, draw_drop, &drop)) { + if (start_drop(&drop) != 0) { beep(); - done = TRUE; - continue; } #else /* @@ -287,5 +381,10 @@ main(int argc GCC_UNUSED, } curs_set(1); endwin(); +#ifdef USE_PTHREADS + printf("Counts per thread:\n"); + for (j = 0; j < MAX_THREADS; ++j) + printf(" %d:%ld\n", j, drop_threads[j].counter); +#endif ExitProgram(EXIT_SUCCESS); }