--- ncurses/SigAction.h +++ ncurses/SigAction.h 2007-01-31 12:39:37.000000000 +0100 @@ -55,6 +55,53 @@ typedef struct sigaction sigaction_t; #endif +#if defined(__GNUC__) && defined(linux) +# if defined __USE_ISOC99 +# define _cat_pragma(exp) _Pragma(#exp) +# define _weak_pragma(exp) _cat_pragma(weak name) +# else +# define _weak_pragma(exp) +# endif +# define _declare(name) __extension__ extern __typeof__(name) name +# define weak_symbol(name) _weak_pragma(name) _declare(name) __attribute__((weak)) +#else +# if defined(linux) && (defined(_REENTRANT) || defined(_THREAD_SAFE)) +# error The ncurses library has to be NPTL thread safe (requires the GCC) +# endif +#endif + +#if defined(linux) && (defined(_REENTRANT) || defined(_THREAD_SAFE)) +# include + +weak_symbol(pthread_sigmask); +weak_symbol(pthread_kill); +weak_symbol(pthread_self); +weak_symbol(pthread_equal); + +static inline int _nc__sigprocmask(int how, const sigset_t *newmask, sigset_t *oldmask) +{ + if (&pthread_sigmask) + return pthread_sigmask(how, newmask, oldmask); + else + return sigprocmask(how, newmask, oldmask); +} +# undef sigprocmask +# define sigprocmask _nc__sigprocmask + +static inline void _nc_kill(SCREEN *scan, int signal) +{ + if (!scan || !scan->_read_thread) + goto out; + if (!&pthread_kill || !&pthread_equal || !&pthread_self) + goto out; + if (pthread_equal(scan->_read_thread, pthread_self())) + goto out; + pthread_kill(scan->_read_thread, signal); +out: + return; +} +#endif + #else /* !HAVE_SIGACTION */ #if HAVE_SIGVEC --- ncurses/curses.priv.h +++ ncurses/curses.priv.h 2007-01-31 12:40:37.000000000 +0100 @@ -48,6 +48,10 @@ #include +#if defined(linux) && (defined(_REENTRANT) || defined(_THREAD_SAFE)) +# include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -594,6 +598,11 @@ struct screen { #define _nc_windows SP->_nc_sp_windows bool _sig_winch; +#if USE_SIGWINCH +# if defined(linux) && (defined(_REENTRANT) || defined(_THREAD_SAFE)) + pthread_t _read_thread; +# endif +#endif SCREEN *_next_screen; /* hashes for old and new lines */ @@ -1214,6 +1223,9 @@ extern NCURSES_EXPORT(void) _nc_scroll_o extern NCURSES_EXPORT(void) _nc_scroll_optimize (void); extern NCURSES_EXPORT(void) _nc_set_buffer (FILE *, bool); extern NCURSES_EXPORT(void) _nc_signal_handler (bool); +#if USE_SIGWINCH +extern NCURSES_EXPORT(void) _nc_thread(SCREEN *); +#endif extern NCURSES_EXPORT(void) _nc_synchook (WINDOW *); extern NCURSES_EXPORT(void) _nc_trace_tries (TRIES *); --- ncurses/base/lib_getch.c +++ ncurses/base/lib_getch.c 2007-01-31 12:41:27.000000000 +0100 @@ -237,6 +237,10 @@ _nc_wgetch(WINDOW *win, if (win == 0 || SP == 0) returnCode(ERR); +#if USE_SIGWINCH + _nc_thread(SP); +#endif + if (cooked_key_in_fifo()) { if (wgetch_should_refresh(win)) wrefresh(win); --- ncurses/base/lib_set_term.c +++ ncurses/base/lib_set_term.c 2007-01-31 13:08:37.000000000 +0100 @@ -144,6 +144,12 @@ delscreen(SCREEN *sp) free(sp->_setbuf); } +#if USE_SIGWINCH +# if defined(linux) && (defined(_REENTRANT) || defined(_THREAD_SAFE)) + sp->_read_thread = (pthread_t)0; +# endif +#endif + free(sp); /* @@ -559,6 +565,15 @@ _nc_setupscreen(int slines, returnCode(ERR); SP->_stdscr = stdscr; +#if USE_SIGWINCH +# if defined(linux) && (defined(_REENTRANT) || defined(_THREAD_SAFE)) + if (&pthread_self) + SP->_read_thread = pthread_self(); + else + SP->_read_thread = (pthread_t)0; +# endif +#endif + returnCode(OK); } --- ncurses/tinfo/lib_setup.c +++ ncurses/tinfo/lib_setup.c 2007-01-31 11:46:17.000000000 +0100 @@ -42,6 +42,7 @@ #include #include /* for MAX_NAME_SIZE */ #include +#include #if SVR4_TERMIO && !defined(_POSIX_SOURCE) #define _POSIX_SOURCE @@ -119,6 +120,13 @@ _nc_handle_sigwinch(int enable) default: /* record a SIGWINCH */ have_sigwinch = 1; +# if defined(linux) && (defined(_REENTRANT) || defined(_THREAD_SAFE)) + scan = _nc_screen_chain; + while (scan) { + _nc_kill(scan, SIGWINCH); + scan = scan->_next_screen; + } +# endif break; case 0: /* temporarily disable the next block */ --- ncurses/tty/lib_tstp.c +++ ncurses/tty/lib_tstp.c 2007-01-31 13:14:40.000000000 +0100 @@ -142,6 +142,11 @@ tstp(int dummy GCC_UNUSED) #ifdef SIGTTOU int sigttou_blocked; #endif +#if USE_SIGWINCH +# if defined(linux) && (defined(_REENTRANT) || defined(_THREAD_SAFE)) + pthread_t reader = (pthread_t)0; +# endif +#endif T(("tstp() called")); @@ -169,6 +174,10 @@ tstp(int dummy GCC_UNUSED) (void) sigaddset(&mask, SIGALRM); #if USE_SIGWINCH (void) sigaddset(&mask, SIGWINCH); +# if defined(linux) && (defined(_REENTRANT) || defined(_THREAD_SAFE)) + reader = SP->_read_thread; + SP->_read_thread = (pthread_t)0; +# endif #endif (void) sigprocmask(SIG_BLOCK, &mask, &omask); @@ -214,6 +223,12 @@ tstp(int dummy GCC_UNUSED) sigaction(SIGTSTP, &oact, NULL); flushinp(); +#if USE_SIGWINCH +# if defined(linux) && (defined(_REENTRANT) || defined(_THREAD_SAFE)) + SP->_read_thread = reader; +# endif +#endif + /* * If the user modified the tty state while suspended, he wants * those changes to stick. So save the new "default" terminal state. @@ -386,6 +401,13 @@ _nc_signal_handler(bool enable) CatchIfDefault(SIGINT, cleanup); CatchIfDefault(SIGTERM, cleanup); #if USE_SIGWINCH +# if defined(linux) && (defined(_REENTRANT) || defined(_THREAD_SAFE)) + if (&pthread_self && &pthread_equal) { + pthread_t current = pthread_self(); + if (!pthread_equal(SP->_read_thread, current)) + SP->_read_thread = current; + } +# endif CatchIfDefault(SIGWINCH, sigwinch); #endif initialized = TRUE; @@ -393,3 +415,25 @@ _nc_signal_handler(bool enable) } returnVoid; } + +#if USE_SIGWINCH +/* + * This is invoked once at the beginning of reading, to remember + * which thread should be interrupted if the SIGWINCH handler is + * called. + */ + +NCURSES_EXPORT(void) +_nc_thread(SCREEN *scan) +{ +# if defined(linux) && (defined(_REENTRANT) || defined(_THREAD_SAFE)) + if (&pthread_self && &pthread_equal) { + pthread_t current = pthread_self(); + if (pthread_equal(SP->_read_thread, current)) + return; + /* Remember the terminal reading thread */ + scan->_read_thread = current; + } +# endif +} +#endif