Date: Wed, 02 Dec 98 15:13:33 -0600 From: "Richard Seaman, Jr." <lists@tar.com> To: "John Birrell" <jb@cimlogic.com.au> Cc: "eischen@vigrid.com" <eischen@vigrid.com>, "freebsd-hackers@FreeBSD.ORG" <freebsd-hackers@FreeBSD.ORG> Subject: Re: pthread_cancel() function... Message-ID: <199812022113.PAA00894@ns.tar.com>
next in thread | raw e-mail | index | archive | help
On Thu, 3 Dec 1998 07:43:36 +1100 (EST), John Birrell wrote: >Richard Seaman, Jr. wrote: >> In the case of libc_r, you probably don't want to alias it >> to _thread_sys_xxx, since you probably want the wrappers for >> the blocking syscalls to be used in libc_r. If you rename >> the uthread syscall wrappers from xxx to _xxx (eg. _read) >> and then implement xxx as a wrapper of _xxx that implements >> cancellation points, you'd be consistent. > >Why do you need a second wrapper? The fact that a syscall has been >wrappered for libc_r is sufficient to include any cancellation checks >in the _existing_ wrapper code. Sure. The problem, as I see it (and I guess I'm not explaining it well), is that you if you wrap it all in one call, you propagate cancellation points to every libc and libc_r function that calls the wrapped call. Taking read as an example, I think you need two versions of read. One that implements cancellation points, that the end user will call. And, one that doesn't, that you would use internally within libc and libc_r, so you don't propagate cancellation points where you're not supposed to have them. >I don't think it is sufficient to just add what you call "wrappers". >AFAIK, the thread cancellation is supposed to occur at any time while >the thread is in one of the specified functions, not just at the beginning >or at the end. This means that code is required to check the thread >state and do things conditionally on that. Well, consider implementing cancellation points like this: int read (......) { .... pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); ret = _read(fd, buf, nbytes); pthread_setcanceltype (oldtype, NULL); return (ret); } Normally you'd expect pthread_setcanceltype to be a cancellation point itself. By setting the cancel type to ASYNCHRONOUS, you're allowing the thread to be cancelled at any time while its in this state. Thus you can be cancelled just before the _read call, just after it, and maybe while you're blocked in _read. What happens if you're blocked in the _read call really depends on how you implement ASYNCHRONOUS cancellation. If you implement pthread_cancel as a signal, PTHREAD_SIG_CANCEL, and if you ensure that the signal handler for PTHREAD_SIG_CANCEL causes _read to return EINTR (at least if the cancellation type is ASYNCHRONOUS), then you'll get out of _read early. With the current signal handling, you would probably have to pre-empt some existing signal (eg. SIGUSR2) to serve as PTHREAD_SIG_CANCEL, and control the end user's access to that signal. >The standard says that certain functions /may/ have cancellation points, >but the "implementation shall not introduce cancellation points into >any other POSIX.1 or C standard functions". Ensuring that this is the >case is the PITA. Thats the point I've been trying to make, apparently without success. >And writing test code that exercises all the possible >combinations is impossible IMHO. Well, with the "two layer" wrapping I was suggesting, you'd never use a function that is a cancellation point within libc, libc_r or within a "normal" syscall. Only functions that are exported by libc or libc_r for use outside the library itself would have cancellation points implemented in them. That way, you could see by inspection where cancellation points exist. To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199812022113.PAA00894>