From 1804be048ac341df4162dc954e7319adb4ce915c Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sat, 30 Apr 2011 16:34:48 +0000 Subject: [PATCH] * fcntl.cc (fcntl64): Call pthread_testcancel. * fhandler_socket.cc (fhandler_socket::connect): Ditto. (fhandler_socket::accept4): Ditto. (fhandler_socket::recvfrom): Ditto. (fhandler_socket::recvmsg): Ditto. (fhandler_socket::sendto): Ditto. (fhandler_socket::sendmsg): Ditto. * flock.cc (lf_setlock): Allow to cancel thread running blocking file lock. Try to make code more readable. (lockf): Call pthread_testcancel. * mmap.cc (msync): Ditto. * posix_ipc.cc (ipc_cond_timedwait): Call pthread::static_cancel_self rather than pthread_testcancel. * select.cc (cygwin_select): Call pthread_testcancel. * syscalls.cc (pread): Ditto. (pwrite): Ditto. (readv): Ditto. (writev): Ditto. (open): Ditto. (close): Ditto. (fsync): Ditto. * termios.cc (tcdrain): Ditto. * thread.cc: Align list of cancellation points with above changes. Mark not-implemented functions, too. (cancelable_wait): Don't set unused object indices to WAIT_FAILED since that could result in wrong behaviour. Set them to the invalid value WAIT_TIMEOUT + 1 instead. --- winsup/cygwin/ChangeLog | 30 ++++++ winsup/cygwin/fcntl.cc | 4 +- winsup/cygwin/fhandler_socket.cc | 12 +++ winsup/cygwin/flock.cc | 69 +++++++++---- winsup/cygwin/mmap.cc | 2 + winsup/cygwin/posix_ipc.cc | 2 +- winsup/cygwin/select.cc | 2 + winsup/cygwin/syscalls.cc | 12 +++ winsup/cygwin/termios.cc | 2 + winsup/cygwin/thread.cc | 161 ++++++++++++++++--------------- 10 files changed, 197 insertions(+), 99 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 5b0d8ae7b..a4b1c2b48 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,33 @@ +2011-04-30 Corinna Vinschen + + * fcntl.cc (fcntl64): Call pthread_testcancel. + * fhandler_socket.cc (fhandler_socket::connect): Ditto. + (fhandler_socket::accept4): Ditto. + (fhandler_socket::recvfrom): Ditto. + (fhandler_socket::recvmsg): Ditto. + (fhandler_socket::sendto): Ditto. + (fhandler_socket::sendmsg): Ditto. + * flock.cc (lf_setlock): Allow to cancel thread running blocking + file lock. Try to make code more readable. + (lockf): Call pthread_testcancel. + * mmap.cc (msync): Ditto. + * posix_ipc.cc (ipc_cond_timedwait): Call pthread::static_cancel_self + rather than pthread_testcancel. + * select.cc (cygwin_select): Call pthread_testcancel. + * syscalls.cc (pread): Ditto. + (pwrite): Ditto. + (readv): Ditto. + (writev): Ditto. + (open): Ditto. + (close): Ditto. + (fsync): Ditto. + * termios.cc (tcdrain): Ditto. + * thread.cc: Align list of cancellation points with above changes. + Mark not-implemented functions, too. + (cancelable_wait): Don't set unused object indices to WAIT_FAILED + since that could result in wrong behaviour. Set them to the invalid + value WAIT_TIMEOUT + 1 instead. + 2011-04-30 Corinna Vinschen * thread.h (class pthread): Add bool member canceled. diff --git a/winsup/cygwin/fcntl.cc b/winsup/cygwin/fcntl.cc index de13f10bf..84e5e5436 100644 --- a/winsup/cygwin/fcntl.cc +++ b/winsup/cygwin/fcntl.cc @@ -1,7 +1,7 @@ /* fcntl.cc: fcntl syscall Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2008, - 2009, 2010 Red Hat, Inc. + 2009, 2010, 2011 Red Hat, Inc. This file is part of Cygwin. @@ -26,6 +26,8 @@ fcntl64 (int fd, int cmd, ...) void *arg = NULL; va_list args; + pthread_testcancel (); + myfault efault; if (efault.faulted (EFAULT)) return -1; diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index d0cf205a6..1151f89fe 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -1026,6 +1026,8 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen) DWORD err; int type; + pthread_testcancel (); + if (!get_inet_addr (name, namelen, &sst, &namelen, &type, connect_secret)) return -1; @@ -1140,6 +1142,8 @@ fhandler_socket::accept4 (struct sockaddr *peer, int *len, int flags) struct sockaddr_storage lpeer; int llen = sizeof (struct sockaddr_storage); + pthread_testcancel (); + int res = 0; while (!(res = wait_for_events (FD_ACCEPT | FD_CLOSE, 0)) && (res = ::accept (get_socket (), (struct sockaddr *) &lpeer, &llen)) @@ -1473,6 +1477,8 @@ ssize_t fhandler_socket::recvfrom (void *ptr, size_t len, int flags, struct sockaddr *from, int *fromlen) { + pthread_testcancel (); + WSABUF wsabuf = { len, (char *) ptr }; WSAMSG wsamsg = { from, from && fromlen ? *fromlen : 0, &wsabuf, 1, @@ -1487,6 +1493,8 @@ fhandler_socket::recvfrom (void *ptr, size_t len, int flags, ssize_t fhandler_socket::recvmsg (struct msghdr *msg, int flags) { + pthread_testcancel (); + /* TODO: Descriptor passing on AF_LOCAL sockets. */ /* Disappointing but true: Even if WSARecvMsg is supported, it's only @@ -1626,6 +1634,8 @@ fhandler_socket::sendto (const void *ptr, size_t len, int flags, { struct sockaddr_storage sst; + pthread_testcancel (); + if (to && !get_inet_addr (to, tolen, &sst, &tolen)) return SOCKET_ERROR; @@ -1640,6 +1650,8 @@ fhandler_socket::sendto (const void *ptr, size_t len, int flags, int fhandler_socket::sendmsg (const struct msghdr *msg, int flags) { + pthread_testcancel (); + /* TODO: Descriptor passing on AF_LOCAL sockets. */ WSABUF wsabuf[msg->msg_iovlen]; diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index 970bde6c1..b4ef9e6a9 100644 --- a/winsup/cygwin/flock.cc +++ b/winsup/cygwin/flock.cc @@ -957,6 +957,20 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) "Win32 pid %lu: %E", block->lf_wid); return EDEADLK; } + + pthread_t thread = pthread::self (); + HANDLE cancel_event = (thread && thread->cancel_event + && thread->cancelstate != PTHREAD_CANCEL_DISABLE) + ? thread->cancel_event : NULL; + + int wait_count = 0; + /* The lock is always the first object. */ + const DWORD WAIT_UNLOCKED = WAIT_OBJECT_0; + /* All other wait objects are variable. */ + DWORD WAIT_PROC_EXITED = WAIT_TIMEOUT + 1; + DWORD WAIT_SIGNAL_ARRIVED = WAIT_TIMEOUT + 1; + DWORD WAIT_THREAD_CANCELED = WAIT_TIMEOUT + 1; + SetThreadPriority (GetCurrentThread (), priority); if (lock->lf_flags & F_POSIX) { @@ -971,15 +985,32 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) NtClose (obj); return EDEADLK; } - HANDLE w4[3] = { obj, proc, signal_arrived }; + + HANDLE w4[4] = { obj, proc, signal_arrived, cancel_event }; + wait_count = 3; + WAIT_PROC_EXITED = WAIT_OBJECT_0 + 1; + WAIT_SIGNAL_ARRIVED = WAIT_OBJECT_0 + 2; + if (cancel_event) + { + wait_count = 4; + WAIT_THREAD_CANCELED = WAIT_OBJECT_0 + 3; + } node->wait (); node->UNLOCK (); - ret = WaitForMultipleObjects (3, w4, FALSE, INFINITE); + ret = WaitForMultipleObjects (wait_count, w4, FALSE, INFINITE); CloseHandle (proc); } else { - HANDLE w4[2] = { obj, signal_arrived }; + HANDLE w4[3] = { obj, signal_arrived, cancel_event }; + wait_count = 2; + WAIT_SIGNAL_ARRIVED = WAIT_OBJECT_0 + 1; + if (cancel_event) + { + wait_count = 3; + WAIT_THREAD_CANCELED = WAIT_OBJECT_0 + 2; + } + node->wait (); node->UNLOCK (); /* Unfortunately, since BSD flock locks are not attached to a @@ -988,7 +1019,7 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) process left accessing this event object. */ do { - ret = WaitForMultipleObjects (2, w4, FALSE, 100L); + ret = WaitForMultipleObjects (wait_count, w4, FALSE, 100L); } while (ret == WAIT_TIMEOUT && get_obj_handle_count (obj) > 1); /* There's a good chance that the above loop is left with @@ -1002,21 +1033,23 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) node->unwait (); NtClose (obj); SetThreadPriority (GetCurrentThread (), old_prio); - switch (ret) + if (ret == WAIT_UNLOCKED) + ; /* The lock object has been set to signalled. */ + else if (ret == WAIT_PROC_EXITED) + ; /* For POSIX locks, the process holding the lock has exited. */ + else if (ret == WAIT_SIGNAL_ARRIVED) { - case WAIT_OBJECT_0: - /* The lock object has been set to signalled. */ - break; - case WAIT_OBJECT_0 + 1: - /* For POSIX locks, the process holding the lock has exited. */ - if (lock->lf_flags & F_POSIX) - break; - /*FALLTHRU*/ - case WAIT_OBJECT_0 + 2: /* A signal came in. */ - _my_tls.call_signal_handler (); - return EINTR; - default: + if (!_my_tls.call_signal_handler ()) + return EINTR; + } + else if (ret == WAIT_THREAD_CANCELED) + { + /* The thread has been sent a cancellation request. */ + pthread::static_cancel_self (); + } + else + { system_printf ("Shouldn't happen! ret = %lu, error: %lu\n", ret, GetLastError ()); return geterrno_from_win_error (); @@ -1490,6 +1523,8 @@ lockf (int filedes, int function, _off64_t size) int cmd; struct __flock64 fl; + pthread_testcancel (); + myfault efault; if (efault.faulted (EFAULT)) return -1; diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc index 8522b6d6d..059daa186 100644 --- a/winsup/cygwin/mmap.cc +++ b/winsup/cygwin/mmap.cc @@ -1169,6 +1169,8 @@ msync (void *addr, size_t len, int flags) syscall_printf ("msync (addr: %p, len %u, flags %x)", addr, len, flags); + pthread_testcancel (); + LIST_LOCK (); if (((uintptr_t) addr % getpagesize ()) diff --git a/winsup/cygwin/posix_ipc.cc b/winsup/cygwin/posix_ipc.cc index 88f5a2e5e..ec6b6c76a 100644 --- a/winsup/cygwin/posix_ipc.cc +++ b/winsup/cygwin/posix_ipc.cc @@ -227,7 +227,7 @@ restart1: break; case WAIT_OBJECT_0 + 2: if (timer_idx != 2) - pthread_testcancel (); + pthread::static_cancel_self (); /*FALLTHRU*/ case WAIT_OBJECT_0 + 3: ret = ETIMEDOUT; diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index 962709605..b3d33c68d 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -96,6 +96,8 @@ cygwin_select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, select_printf ("%d, %p, %p, %p, %p", maxfds, readfds, writefds, exceptfds, to); + pthread_testcancel (); + if (!readfds) readfds = dummy_readfds; if (!writefds) diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 40b590af7..ee5704095 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -912,6 +912,8 @@ EXPORT_ALIAS (read, _read) extern "C" ssize_t pread (int fd, void *ptr, size_t len, _off64_t off) { + pthread_testcancel (); + ssize_t res; cygheap_fdget cfd (fd); if (cfd < 0) @@ -927,6 +929,8 @@ pread (int fd, void *ptr, size_t len, _off64_t off) extern "C" ssize_t pwrite (int fd, void *ptr, size_t len, _off64_t off) { + pthread_testcancel (); + ssize_t res; cygheap_fdget cfd (fd); if (cfd < 0) @@ -956,6 +960,8 @@ EXPORT_ALIAS (write, _write) extern "C" ssize_t readv (int fd, const struct iovec *const iov, const int iovcnt) { + pthread_testcancel (); + extern int sigcatchers; const int e = get_errno (); @@ -1039,6 +1045,8 @@ done: extern "C" ssize_t writev (const int fd, const struct iovec *const iov, const int iovcnt) { + pthread_testcancel (); + int res = -1; const ssize_t tot = check_iovec_for_write (iov, iovcnt); @@ -1096,6 +1104,7 @@ open (const char *unix_path, int flags, ...) mode_t mode = 0; syscall_printf ("open (%s, %p)", unix_path, flags); + pthread_testcancel (); myfault efault; if (efault.faulted (EFAULT)) /* errno already set */; @@ -1206,6 +1215,8 @@ close (int fd) syscall_printf ("close (%d)", fd); + pthread_testcancel (); + MALLOC_CHECK; cygheap_fdget cfd (fd, true); if (cfd < 0) @@ -1480,6 +1491,7 @@ _fstat_r (struct _reent *ptr, int fd, struct __stat32 *buf) extern "C" int fsync (int fd) { + pthread_testcancel (); cygheap_fdget cfd (fd); if (cfd < 0) { diff --git a/winsup/cygwin/termios.cc b/winsup/cygwin/termios.cc index 608f03009..a59bbd2cc 100644 --- a/winsup/cygwin/termios.cc +++ b/winsup/cygwin/termios.cc @@ -48,6 +48,8 @@ out: extern "C" int tcdrain (int fd) { + pthread_testcancel (); + int res = -1; termios_printf ("tcdrain"); diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 10fc2c66b..b4a9b2982 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -568,79 +568,80 @@ pthread::cancel () /* TODO: Insert pthread_testcancel into the required functions. Here are the lists of required and optional functions per POSIX.1-2001 - and POSIX.1-2008. A start (*) indicates that the Cygwin function already - is a cancellation point (aka "calls pthread_testcancel"). + and POSIX.1-2008. A star (*) indicates that the Cygwin function already + is a cancellation point (aka "calls pthread_testcancel"), an o (o) + indicates that the function is not implemented in Cygwin. Required cancellation points: - accept () - aio_suspend () - clock_nanosleep () + * accept () + o aio_suspend () + o clock_nanosleep () * close () - connect () + * connect () * creat () - fcntl () F_SETLKW - fdatasync () - fsync () - getmsg () - getpmsg () - lockf () F_LOCK + * fcntl () F_SETLKW + * fdatasync () + * fsync () + o getmsg () + o getpmsg () + * lockf () F_LOCK * mq_receive () * mq_send () * mq_timedreceive () * mq_timedsend () msgrcv () msgsnd () - msync () - nanosleep () - open () - openat () + * msync () + * nanosleep () + * open () + * openat () * pause () poll () - pread () + * pread () pselect () * pthread_cond_timedwait () * pthread_cond_wait () * pthread_join () * pthread_testcancel () - putmsg () - putpmsg () - pwrite () - read () - readv () - recv () - recvfrom () - recvmsg () + o putmsg () + o putpmsg () + * pwrite () + * read () + * readv () + * recv () + * recvfrom () + * recvmsg () select () * sem_timedwait () * sem_wait () - send () - sendmsg () - sendto () + * send () + * sendmsg () + * sendto () * sigpause () * sigsuspend () - sigtimedwait () - sigwait () - sigwaitinfo () + o sigtimedwait () + * sigwait () + * sigwaitinfo () * sleep () * system () - tcdrain () + * tcdrain () * usleep () * wait () * wait3() - waitid () + o waitid () * waitpid () - write () - writev () + * write () + * writev () Optional cancellation points: access () asctime () asctime_r () - catclose () - catgets () - catopen () + catclose () Implemented externally: libcatgets + catgets () Implemented externally: libcatgets + catopen () Implemented externally: libcatgets chmod () chown () closedir () @@ -648,18 +649,18 @@ pthread::cancel () ctermid () ctime () ctime_r () - dbm_close () - dbm_delete () - dbm_fetch () - dbm_nextkey () - dbm_open () - dbm_store () + dbm_close () Implemented externally: libgdbm + dbm_delete () Implemented externally: libgdbm + dbm_fetch () Implemented externally: libgdbm + dbm_nextkey () Implemented externally: libgdbm + dbm_open () Implemented externally: libgdbm + dbm_store () Implemented externally: libgdbm dlclose () dlopen () dprintf () endgrent () endhostent () - endnetent () + o endnetent () endprotoent () endpwent () endservent () @@ -669,15 +670,15 @@ pthread::cancel () fchmodat () fchown () fchownat () - fclose () - fcntl () (any value) + * fclose () + * fcntl () (any value) fflush () fgetc () fgetpos () fgets () fgetwc () fgetws () - fmtmsg () + o fmtmsg () fopen () fpathconf () fprintf () @@ -706,7 +707,7 @@ pthread::cancel () getchar () getchar_unlocked () getcwd () - getdate () + o getdate () getdelim () getgrent () getgrgid () @@ -722,9 +723,9 @@ pthread::cancel () getlogin () getlogin_r () getnameinfo () - getnetbyaddr () - getnetbyname () - getnetent () + o getnetbyaddr () + o getnetbyname () + o getnetent () getopt () (if opterr is nonzero) getprotobyname () getprotobynumber () @@ -745,15 +746,15 @@ pthread::cancel () getwchar () getwd () glob () - iconv_close () - iconv_open () + iconv_close () Implemented externally: libiconv + iconv_open () Implemented externally: libiconv ioctl () link () linkat () - lio_listio () + o lio_listio () localtime () localtime_r () - lockf () + * lockf () lseek () lstat () mkdir () @@ -776,28 +777,28 @@ pthread::cancel () posix_fallocate () posix_madvise () posix_openpt () - posix_spawn () - posix_spawnp () - posix_trace_clear () - posix_trace_close () - posix_trace_create () - posix_trace_create_withlog () - posix_trace_eventtypelist_getnext_id () - posix_trace_eventtypelist_rewind () - posix_trace_flush () - posix_trace_get_attr () - posix_trace_get_filter () - posix_trace_get_status () - posix_trace_getnext_event () - posix_trace_open () - posix_trace_rewind () - posix_trace_set_filter () - posix_trace_shutdown () - posix_trace_timedgetnext_event () - posix_typed_mem_open () + o posix_spawn () + o posix_spawnp () + o posix_trace_clear () + o posix_trace_close () + o posix_trace_create () + o posix_trace_create_withlog () + o posix_trace_eventtypelist_getnext_id () + o posix_trace_eventtypelist_rewind () + o posix_trace_flush () + o posix_trace_get_attr () + o posix_trace_get_filter () + o posix_trace_get_status () + o posix_trace_getnext_event () + o posix_trace_open () + o posix_trace_rewind () + o posix_trace_set_filter () + o posix_trace_shutdown () + o posix_trace_timedgetnext_event () + o posix_typed_mem_open () printf () - psiginfo () - psignal () + o psiginfo () + o psignal () pthread_rwlock_rdlock () pthread_rwlock_timedrdlock () pthread_rwlock_timedwrlock () @@ -825,7 +826,7 @@ pthread::cancel () semop () setgrent () sethostent () - setnetent () + o setnetent () setprotoent () setpwent () setservent () @@ -908,7 +909,7 @@ cancelable_wait (HANDLE object, DWORD timeout, DWORD cancel_n; if (cancel_action == cw_no_cancel || !pthread::is_good_object (&thread) || thread->cancelstate == PTHREAD_CANCEL_DISABLE) - cancel_n = (DWORD) -1; + cancel_n = WAIT_TIMEOUT + 1; else { cancel_n = WAIT_OBJECT_0 + num++; @@ -917,7 +918,7 @@ cancelable_wait (HANDLE object, DWORD timeout, DWORD sig_n; if (sig_wait == cw_sig_nosig || &_my_tls != _main_tls) - sig_n = (DWORD) -1; + sig_n = WAIT_TIMEOUT + 1; else { sig_n = WAIT_OBJECT_0 + num++;