Re: Small fixes for 2.1.23

Linus Torvalds (torvalds@cs.Helsinki.FI)
Mon, 27 Jan 1997 11:00:49 +0200 (EET)

On Sun, 26 Jan 1997, Ion Badulescu wrote:
> Hi everyone,

Hi there,

> The following patch, relative to 2.1.23, corrects the following
> bugs/features:

Ok, the rest of these look ok, but I'm not applying it because of the
"poll" buglet..

> - the binfmt_script bug which prevents killall from working on scripts
> - the softdog bug which prevents a new daemon from opening the device if
> NO_WAY_OUT is defined and the old daemon is killed (e.g. when changing
> initlevels)
> - the floppy bug - duplicated MODULE_PARM(floppy, "s") - which prevents
> floppy.c from compiling
> - updates for drivers/sound/* (select->poll)
> - finally, my own /proc/swaps patch updated for 2.1.23

The select->poll changes make the source compile, but do not actually do
quite the right thing. The poll changes weren't only a matter of naming
changes, but also changed semantics somewhat (I don't do naming changes
just to change names usually: there is a reason why I didn't want
unmodified code to compile - it needs to get subtly fixed first).

Anyway, I should have made the changes clear in my announcement of 2.1.23,
but I was too lazy. The changes in the poll behaviour can be broken down
into four different sub-areas:

- name change: "select" -> "poll" on the VFS layer
- argument change: only "struct file *" and "poll_table *"
- return change: instead of returning 0/1, it returns a bitmask of POLL
events. The old select code was called three times (once for SEL_IN,
once for SEL_OUT and finally once for SEL_EX), while poll() is called
just once, and returns a bitmask of all active events.
- calling change: we don't call the function twice (like we used to),
instead the function is supposed to add the wait entry to the
poll_table _first_ before doing the tests (so that any change in state
will wake up up correctly without any races - calling the function
twice used to do that for us, but was inefficient)

The changes can best be explained by showing a trivial example of a
select function that got changed:

static int aux_select(struct inode *inode, struct file *file,
int sel_type, select_table * wait)
if (sel_type != SEL_IN)
return 0;
if (aux_ready)
return 1;
select_wait(&queue->proc_list, wait);
return 0;

the above got changed to:

static unsigned int aux_poll(struct file *file,
poll_table * wait)
poll_wait(&queue->proc_list, wait);
if (aux_ready)
return 0;

Note the differences: calling arguments changed, but most notably the
return values changed. Also, the select_wait() _used_ to be last (and only
done if we return zero), but in the poll version it is done first and done
regardless of what we return (that avoids a race condition - the way linux
does wakeups is so subtle to be almost impossible to explain without a
whiteboard. Very clever, but subtle).

The above is just a trivial example, and it gets a bit more complex when
the old select code used to check for all of SEL_IN/SEL_OUT/SEL_EX
(because then the return bitmask becomes more complex to calculate), but
it shows the most important changes..