Re: Per-descriptor state
On 2023-05-08 02:09, Johnny Billquist wrote: On 2023-05-08 01:30, David Holland wrote> On Fri, May 05, 2023 at 09:44:25PM -0400, Mouse wrote: > not nearly as > horrible as, say, the hack I once implemented where calling > wait4(0x456d756c,(int *)0x61746f72,0x4d616769,(struct rusage *)0x633a2d29) ^^ > would produce suitably magic effects. (This was on a 32-bit machine.) surely you mean 39! Hmm? "EmulatorMagic:-)" don't do it for you, you want "EmulatorMagic:=)" ? I wonder what the emoji " :=) " means... Double nose? Ok. I'm being very silly. I need to go to bed... :-) And I'm clearly half asleep already. Sorry... :-9 it was... Johnny -- Johnny Billquist || "I'm on a bus || on a psychedelic trip email: b...@softjar.se || Reading murder books pdp is alive! || tryin' to stay hip" - B. Idol
Re: Per-descriptor state
On Mon, May 08, 2023 at 12:36:21AM +, David Holland wrote: > I... completely failed to recognize it as an emoji and assumed it was > supposed to be -9 to forcibly shut something down. emoji. smiley. yeah -- David A. Holland dholl...@netbsd.org
Re: Per-descriptor state
On Mon, May 08, 2023 at 02:09:07AM +0200, Johnny Billquist wrote: > > > not nearly as > > > horrible as, say, the hack I once implemented where calling > > > wait4(0x456d756c,(int *)0x61746f72,0x4d616769,(struct rusage > > > *)0x633a2d29) > > > > ^^ > > > would produce suitably magic effects. (This was on a 32-bit machine.) > > > > surely you mean 39! > > Hmm? > > "EmulatorMagic:-)" don't do it for you, you want "EmulatorMagic:=)" ? I... completely failed to recognize it as an emoji and assumed it was supposed to be -9 to forcibly shut something down. :-| -- David A. Holland dholl...@netbsd.org
Re: Per-descriptor state
On 2023-05-08 01:30, David Holland wrote> On Fri, May 05, 2023 at 09:44:25PM -0400, Mouse wrote: > not nearly as > horrible as, say, the hack I once implemented where calling > wait4(0x456d756c,(int *)0x61746f72,0x4d616769,(struct rusage *)0x633a2d29) ^^ > would produce suitably magic effects. (This was on a 32-bit machine.) surely you mean 39! Hmm? "EmulatorMagic:-)" don't do it for you, you want "EmulatorMagic:=)" ? I wonder what the emoji " :=) " means... Double nose? Ok. I'm being very silly. I need to go to bed... :-) Johnny -- Johnny Billquist || "I'm on a bus || on a psychedelic trip email: b...@softjar.se || Reading murder books pdp is alive! || tryin' to stay hip" - B. Idol
Re: Per-descriptor state
On Fri, May 05, 2023 at 09:44:25PM -0400, Mouse wrote: > >>> But I kind of think it'd be preferable to make a way to clone a > >>> second independent struct file for the same socket than to start > >>> mucking with per-descriptor state. > >> [...] it should be easy to extend dup3() to make that possible [...] > > If we were to add such a thing it should be called something else, > > not dup, because it's a fundamentally different operation from dup > > and we don't need people confusing them. > > Different? Some. But not very. It _is_ closely related to dup(). I > don't think dup3() would be a horrible way to do it - There's already a dup3(). But ignoring that... yes, it's quite significant, it constructs a materially different kind of additional reference. For everyone who knows the internal structure of references, which is probably everyone reading this list, it's easy to understand what the semantics are and what the difference between the two operations; for everyone else, which is most of the world and most of the people who will ever use the call, it is _not_ clear and if the two cases aren't made overtly distinct they'll routinely mix them up and get in trouble. Even if they are made overtly distinct you'll still get bozos making wrong proclamations about them in places like stackoverflow. *puts on his "taught this to undergrads for many years" hat* > not nearly as > horrible as, say, the hack I once implemented where calling > wait4(0x456d756c,(int *)0x61746f72,0x4d616769,(struct rusage *)0x633a2d29) ^^ > would produce suitably magic effects. (This was on a 32-bit machine.) surely you mean 39! > But, honestly, when I saw the idea my reaction was to make it a new > operation to fcntl. F_REOPEN, say, since it's creating new per-open > state. Or, if you want to be all overloady, how about > open(0,O_REOPEN,existingfd)? It _is_ creating new per-open state, so > open is in _some_ sense right. > > My choice, for what it's worth, would be fcntl, dup3 second, with > O_REOPEN a distant third. fcntl is inherently terrible and shouldn't get new ops or use cases (there is absolutely no reason to prefer it to a new syscall except for conservation of syscall numbers, which isn't a useful thing). Should be something like reopen(fd, flags). Or it could be open("/dev/fd/%d", flags); except that neither the pathname nor the semantics of /dev/fd are reliably portable. (...passing a fd as a 3rd argument to open is really horrible; that's a mode_t, not a fd) -- David A. Holland dholl...@netbsd.org
Re: Per-descriptor state
On Thu, May 04, 2023 at 08:40:49AM -0400, Mouse wrote: > >> I can't think of any at all; to begin with it's limited to forks > >> that don't exec > [...] > > Well, except for libraries that open fds internally, without exposing > them to the calling code. Depending on the user case, they may want > them closed if the application forks. > > [...] > > Because one wants to exec a child process, maybe? If the fork is going to exec, O_CLOEXEC is sufficient; I can't think of any realistic situation where having a second reference to the same file for at most few extra milliseconds can actually hurt anything. -- David A. Holland dholl...@netbsd.org
Re: Per-descriptor state
>>> But I kind of think it'd be preferable to make a way to clone a >>> second independent struct file for the same socket than to start >>> mucking with per-descriptor state. >> [...] it should be easy to extend dup3() to make that possible [...] > If we were to add such a thing it should be called something else, > not dup, because it's a fundamentally different operation from dup > and we don't need people confusing them. Different? Some. But not very. It _is_ closely related to dup(). I don't think dup3() would be a horrible way to do it - not nearly as horrible as, say, the hack I once implemented where calling wait4(0x456d756c,(int *)0x61746f72,0x4d616769,(struct rusage *)0x633a2d29) would produce suitably magic effects. (This was on a 32-bit machine.) But, honestly, when I saw the idea my reaction was to make it a new operation to fcntl. F_REOPEN, say, since it's creating new per-open state. Or, if you want to be all overloady, how about open(0,O_REOPEN,existingfd)? It _is_ creating new per-open state, so open is in _some_ sense right. My choice, for what it's worth, would be fcntl, dup3 second, with O_REOPEN a distant third. /~\ The ASCII Mouse \ / Ribbon Campaign X Against HTMLmo...@rodents-montreal.org / \ Email! 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B
Re: Per-descriptor state
>>> I should probably add [close-on-fork] here, then, though use cases >>> will likely be rare. I can think of only one program I wrote where >>> it'd be useful; I created a "close these fds post-fork" data >>> structure internally. >> I can't think of any at all; to begin with it's limited to forks >> that don't exec, and unless just using it for convenience as you're >> probably suggesting, Yes. If the application does all the forking (ie, except for forks inside libraries, for which see below), it is just convenience, freeing the application from keeping track of which fds need closing. Well, except for libraries that open fds internally, without exposing them to the calling code. Depending on the user case, they may want them closed if the application forks. >> it only applies when also using threads, and if one's using threads >> why is one also using forks? Because one wants to exec a child process, maybe? >> So it seems like it's limited to badly designed libraries that want >> to fork behind the caller's back instead of setting up their forks >> at initialization time. Or something. What about libraries that fork _not_ behind the caller's back? (system(3) being, perhaps, the poster child.) > Or it is needed for a little used application called Firefox. What part of "badly designed" does that not fit? (Okay, admittedly, I don't know what Firefox looks like internally. But the UI design is bad enough I would expect the internals to be little better.) /~\ The ASCII Mouse \ / Ribbon Campaign X Against HTMLmo...@rodents-montreal.org / \ Email! 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B
Re: Per-descriptor state
On Thu, May 04, 2023 at 09:58:49AM +0100, Robert Swindells wrote: > > David Holland wrote: > >On Sun, Apr 30, 2023 at 09:44:49AM -0400, Mouse wrote: > > > > Close-on-fork is apparently either coming or already here, not sure > > > > which, but it's also per-descriptor. > > > > > > I should probably add that here, then, though use cases will likely be > > > rare. I can think of only one program I wrote where it'd be useful; I > > > created a "close these fds post-fork" data structure internally. > > > >I can't think of any at all; to begin with it's limited to forks that > >don't exec, and unless just using it for convenience as you're > >probably suggesting, it only applies when also using threads, and if > >one's using threads why is one also using forks? So it seems like it's > >limited to badly designed libraries that want to fork behind the > >caller's back instead of setting up their forks at initialization > >time. Or something. > > Or it is needed for a little used application called Firefox. For a sandbox, something like closefrom is actually much preferred as you don't know what else has opened file descriptors. I really question the sanity of close-on-fork... Joerg
Re: Per-descriptor state
David Holland wrote: >On Sun, Apr 30, 2023 at 09:44:49AM -0400, Mouse wrote: > > > Close-on-fork is apparently either coming or already here, not sure > > > which, but it's also per-descriptor. > > > > I should probably add that here, then, though use cases will likely be > > rare. I can think of only one program I wrote where it'd be useful; I > > created a "close these fds post-fork" data structure internally. > >I can't think of any at all; to begin with it's limited to forks that >don't exec, and unless just using it for convenience as you're >probably suggesting, it only applies when also using threads, and if >one's using threads why is one also using forks? So it seems like it's >limited to badly designed libraries that want to fork behind the >caller's back instead of setting up their forks at initialization >time. Or something. Or it is needed for a little used application called Firefox.
Re: Per-descriptor state
On Sun, Apr 30, 2023 at 10:50:51PM +0700, Robert Elz wrote: > Date:Sun, 30 Apr 2023 05:25:41 + > From:David Holland > Message-ID: > > | Close-on-fork is apparently either coming or already here, not sure > | which, but it's also per-descriptor. > > We don't have it, but it will be in Posix-8. Largely inspired by the > needs of threaded programs (without lots of critical sections, one cannot > otherwise open anything if another thread might fork, there's no > way to avoid race conditions, hence O_CLOFORK on open ... not sure if > anyone has thought of a way to add it to socket() - that doesn't look > to be trivial, though it might be possible to abuse one of the params > it has - probably domain - and add flags in upper bits ... while having > it able to be set/reset via fcntl is useful, to work, it needs to be > able to be set atomically with the operation that creates the fd, and > having it default "on", which would work, would break almost all existing > non-trivial code). Given that the trend is to just add extra calls with flags arguments without even pausing to consider, I'd be surprised if nobody's banged out a socket4() yet. > | But I kind of think it'd be preferable to make a way to > | clone a second independent struct file for the same socket than to > | start mucking with per-descriptor state. > > When I saw mouse's message, I was thinking the exact same thing, > and it should be easy to extend dup3() to make that possible If we were to add such a thing it should be called something else, not dup, because it's a fundamentally different operation from dup and we don't need people confusing them. > - however > I'm not sure what effects that might have on the semantics of sockets > (what assumptions the current code might make about there being only > one struct file, with all it contains, for a socket). Indeed :-| -- David A. Holland dholl...@netbsd.org
Re: Per-descriptor state
On Sun, Apr 30, 2023 at 09:44:49AM -0400, Mouse wrote: > > Close-on-fork is apparently either coming or already here, not sure > > which, but it's also per-descriptor. > > I should probably add that here, then, though use cases will likely be > rare. I can think of only one program I wrote where it'd be useful; I > created a "close these fds post-fork" data structure internally. I can't think of any at all; to begin with it's limited to forks that don't exec, and unless just using it for convenience as you're probably suggesting, it only applies when also using threads, and if one's using threads why is one also using forks? So it seems like it's limited to badly designed libraries that want to fork behind the caller's back instead of setting up their forks at initialization time. Or something. > > The thing is, per-descriptor state is a mess and it shouldn't be > > allowed to proliferate. The reason: the descriptor is an array > > index. There's plenty of room to store stuff in the object it looks > > up (that is, struct file) but storing stuff on the key side of the > > array is a problem. > > (References to -current here really mean "filedesc.h 1.70 according to > cvsweb.netbsd.org".) > > [...] I had forgotten how much crap we'd added on behalf of the silly broken close scheme. So all those costs have been paid already. :-| > > (Then there's also another issue, which is that in nearly all cases > > nonblocking I/O is a workaround for interface bugs, e.g. nonblocking > > accept or open of dialout modem devices, or for structural problems > > in software that also needs to use the same file handle, like your > > original problem with curses. In the long run it's probably better to > > kill off the reasons to want to use nonblocking I/O at all.) > > And replace nbio with...what? Multiple threads doing blocking calls? > Or do you think everything should be nonblocking by default, with > blocking behaviour implemented userland-side? Or am I completely > misinterpreting somehow? select? -- David A. Holland dholl...@netbsd.org
Re: Per-descriptor state
In article <21465.1682869...@jacaranda.noi.kre.to>, Robert Elz wrote: >Date:Sun, 30 Apr 2023 05:25:41 + >From:David Holland >Message-ID: > > | Close-on-fork is apparently either coming or already here, not sure > | which, but it's also per-descriptor. > >We don't have it, but it will be in Posix-8. Largely inspired by the >needs of threaded programs (without lots of critical sections, one cannot >otherwise open anything if another thread might fork, there's no >way to avoid race conditions, hence O_CLOFORK on open ... not sure if >anyone has thought of a way to add it to socket() - that doesn't look >to be trivial, though it might be possible to abuse one of the params >it has - probably domain - and add flags in upper bits ... while having >it able to be set/reset via fcntl is useful, to work, it needs to be >able to be set atomically with the operation that creates the fd, and >having it default "on", which would work, would break almost all existing >non-trivial code). We already abuse "type": The following flags can be or'ed to the type to condition the returned file descriptor: The following flags are valid: SOCK_CLOEXEC Set the close on exec property. SOCK_NONBLOCK Sets non-blocking I/O. SOCK_NOSIGPIPE Return EPIPE instead of raising SIGPIPE. christos
Re: Per-descriptor state
>> Close-on-fork is apparently either coming or already here, [...] > We don't have it, but it will be in Posix-8. [...] not sure if > anyone has thought of a way to add it to socket() - It's looking to me as though more and more syscalls are having to grow flags arguments to do things right. Auto-close-on-fork for socket(), accept(), and socketpair(); per-operation non-blocking for at least some half-dozen calls I don't see how to avoid it for socket(). For accept(), it could be shoehorned into a SOL_SOCKET sockopt (SO_AUTO_CLOFORK_ON_ACCEPT, say, better name welcomed). > that doesn't look to be trivial, though it might be possible to abuse > one of the params [socket()] has - probably domain - and add flags in > upper bits ... Possible? Probably. Good? No, IMO. > while having it able to be set/reset via fcntl is useful, to work, it > needs to be able to be set atomically with the operation that creates > the fd, Well, to work for one particularly important use case. It can work just fine for various other use cases without that. > and having it default "on", which would work, would break almost all > existing non-trivial code). What about having it default to a per-proces (or per-thread) settable state? Mouse
Re: Per-descriptor state
Date:Sun, 30 Apr 2023 05:25:41 + From:David Holland Message-ID: | Close-on-fork is apparently either coming or already here, not sure | which, but it's also per-descriptor. We don't have it, but it will be in Posix-8. Largely inspired by the needs of threaded programs (without lots of critical sections, one cannot otherwise open anything if another thread might fork, there's no way to avoid race conditions, hence O_CLOFORK on open ... not sure if anyone has thought of a way to add it to socket() - that doesn't look to be trivial, though it might be possible to abuse one of the params it has - probably domain - and add flags in upper bits ... while having it able to be set/reset via fcntl is useful, to work, it needs to be able to be set atomically with the operation that creates the fd, and having it default "on", which would work, would break almost all existing non-trivial code). | But I kind of think it'd be preferable to make a way to | clone a second independent struct file for the same socket than to | start mucking with per-descriptor state. When I saw mouse's message, I was thinking the exact same thing, and it should be easy to extend dup3() to make that possible - however I'm not sure what effects that might have on the semantics of sockets (what assumptions the current code might make about there being only one struct file, with all it contains, for a socket). kre
Re: Per-descriptor state
> Close-on-fork is apparently either coming or already here, not sure > which, but it's also per-descriptor. I should probably add that here, then, though use cases will likely be rare. I can think of only one program I wrote where it'd be useful; I created a "close these fds post-fork" data structure internally. > The thing is, per-descriptor state is a mess and it shouldn't be > allowed to proliferate. The reason: the descriptor is an array > index. There's plenty of room to store stuff in the object it looks > up (that is, struct file) but storing stuff on the key side of the > array is a problem. (References to -current here really mean "filedesc.h 1.70 according to cvsweb.netbsd.org".) Looking at the include files, it looks to me as though descriptors are indices into an array of structs (struct fdfile) in -current or 5.2, or an index into two parallel arrays of pointers and flags in 1.4T. Those then point to the structs file (the per-open state). It's true the flags fields are chars (two bits used in 1.4T, two separate chars storing one bit each in 5.2 or -current). But it's a far cry from being as bad as you outline. There are multiple bits free, and, even if they run out, growing them from chars is a low (memory) cost on 1.4T and probably zero on 5.2 and -current on most ports. > For a couple bits you can mask them off from the pointer (though even > that's abusive); If that were what were being done, I would agree it's abusive. > more than that and suddenly you need to double the size of the > fdtable so it contains an extra machine word for random state bits as > well as the pointer to the struct file. That is quite possibly why 1.4T uses parallel arrays rather than an array of structs. In 5.2 and -current, there is enough additional state that someone (rightly, IMO) decided it wasn't worth the code complexity of keeping parallel arrays. (See struct fdfile in sys/filedesc.h for the additional state I'm talking about.) > (Then there's also another issue, which is that in nearly all cases > nonblocking I/O is a workaround for interface bugs, e.g. nonblocking > accept or open of dialout modem devices, or for structural problems > in software that also needs to use the same file handle, like your > original problem with curses. In the long run it's probably better to > kill off the reasons to want to use nonblocking I/O at all.) And replace nbio with...what? Multiple threads doing blocking calls? Or do you think everything should be nonblocking by default, with blocking behaviour implemented userland-side? Or am I completely misinterpreting somehow? > (also, "mirabile visu") What did I write? *checks* Oops. Thanks. /~\ The ASCII Mouse \ / Ribbon Campaign X Against HTMLmo...@rodents-montreal.org / \ Email! 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B
Re: Per-descriptor state
On Sun, Apr 30, 2023 at 12:49:03AM -0400, Mouse wrote: > This is pushing towards making it per-descriptor state. At present, > the versions I have don't have anything but close-on-exec as true > per-descriptor state. A quick look at 9.1 and cvsweb.netbsd.org > (which, mirabilu visu, actually works for me, unlike www.netbsd.org and > mail-index.netbsd.org) sys/sys/filedesc.h makes me think that that's > true of them as well. Close-on-fork is apparently either coming or already here, not sure which, but it's also per-descriptor. The thing is, per-descriptor state is a mess and it shouldn't be allowed to proliferate. The reason: the descriptor is an array index. There's plenty of room to store stuff in the object it looks up (that is, struct file) but storing stuff on the key side of the array is a problem. For a couple bits you can mask them off from the pointer (though even that's abusive); more than that and suddenly you need to double the size of the fdtable so it contains an extra machine word for random state bits as well as the pointer to the struct file. Granted, it's not like this is going to make any machine (that can run Unix at all) tip over from KVA exhaustion, but it's untidy, messy, wasteful, and generally offensive to cleanliness. In general I think there is very little reason to have per-descriptor (rather than per-open) state and the only really valid use cases are those that pertain specifically to individual descriptor numbers, which in turn is pretty much limited to close behavior like close-on-exec. Granted, that's for files, where if you want two independent opens of the same file it's mostly not difficult to get them. For sockets that isn't a thing. But I kind of think it'd be preferable to make a way to clone a second independent struct file for the same socket than to start mucking with per-descriptor state. (Then there's also another issue, which is that in nearly all cases nonblocking I/O is a workaround for interface bugs, e.g. nonblocking accept or open of dialout modem devices, or for structural problems in software that also needs to use the same file handle, like your original problem with curses. In the long run it's probably better to kill off the reasons to want to use nonblocking I/O at all.) (also, "mirabile visu") -- David A. Holland dholl...@netbsd.org
Per-descriptor state
Back in late March, I wrote here (under the Subject: Re: flock(2): locking against itself?) about a locking issue, which drifted into discussing per-descriptor state versus per-open state (thank you dholland for that phrasing!) versus backing-object state. In particular, someone (I forget who) said that non-blocking really should be per-operation rather than being state anywhere. That's correct, but, thinking about it since then, that is not as easy as one might wish, because there are quite a number of calls that can be affected. (Offhand: {,p}{read,write}{,v}, connect, accept, {send,recv}{,msg}, sendto, recvfrom. There are probably others, but this is sixteen already - though I'm not sure p{read,write}{,v} need the option; are there any seekable objects on which non-blocking is significant?) Some of these, such as send*, already have a flags argument that could grow a new bit to indicate nonblocking, but the rest - more than half - would need to have an alternative version created with a flags field, or some such. While hardly impossible, this gets annoying, and indeed might be best addressed by (to use read() as an example) making the real syscall backing read() always take a flags argument, with the libc stub supplying a fixed value for the flags when the flagless API is called. This is pushing towards making it per-descriptor state. At present, the versions I have don't have anything but close-on-exec as true per-descriptor state. A quick look at 9.1 and cvsweb.netbsd.org (which, mirabilu visu, actually works for me, unlike www.netbsd.org and mail-index.netbsd.org) sys/sys/filedesc.h makes me think that that's true of them as well. For backward compatibility, I would be inclined to leave the existing mechanisms in place, theoretically to be removed eventually. This also means divorcing "non-blocking open" from "non-blocking I/O after open". So: does anyone have any comments on the above analysis, or thoughts on good, bad, or even just notable effects making it real per-descriptor state might have? /~\ The ASCII Mouse \ / Ribbon Campaign X Against HTMLmo...@rodents-montreal.org / \ Email! 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B