This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Strange code in selectors.KqueueSelector
Type: enhancement Stage: resolved
Components: Library (Lib) Versions: Python 3.6
process
Status: closed Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Demur Rumed, dabeaz, neologix, xiang.zhang
Priority: normal Keywords:

Created on 2016-07-01 15:33 by dabeaz, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (8)
msg269676 - (view) Author: David Beazley (dabeaz) Date: 2016-07-01 15:33
Not so much a bug, but an observation based on reviewing the implementation of the selectors.KqueueSelector class.  In that class there is the select() method:

        def select(self, timeout=None):
            timeout = None if timeout is None else max(timeout, 0)
            max_ev = len(self._fd_to_key)
            ready = []
            try:
                kev_list = self._kqueue.control(None, max_ev, timeout)
            except InterruptedError:
                return ready
            for kev in kev_list:
                fd = kev.ident
                flag = kev.filter
                events = 0
                if flag == select.KQ_FILTER_READ:
                    events |= EVENT_READ
                if flag == select.KQ_FILTER_WRITE:
                    events |= EVENT_WRITE

                key = self._key_from_fd(fd)
                if key:
                    ready.append((key, events & key.events))
            return ready

The for-loop looks like it might be checking flags against some kind of bit-mask in order to build events.  However, if so, the code just looks wrong.  Wouldn't it use the '&' operator (or some variant) instead of '==' like this?

            for kev in kev_list:
		fd = kev.ident
                flag = kev.filter
                events = 0
                if flag & select.KQ_FILTER_READ:
                    events |= EVENT_READ
                if flag & select.KQ_FILTER_WRITE:
		    events |= EVENT_WRITE

If it's not a bit-mask, then wouldn't the code be simplified by something like this?

            for kev in kev_list:
		fd = kev.ident
                flag = kev.filter
                if flag == select.KQ_FILTER_READ:
                    events = EVENT_READ
                elif flag == select.KQ_FILTER_WRITE:
		    events = EVENT_WRITE


Again, not sure if this is a bug or not. It's just something that looks weirdly off.
msg269682 - (view) Author: Xiang Zhang (xiang.zhang) * (Python committer) Date: 2016-07-01 18:34
EVENT_* and KQ_FILTER_* are two different sets of constants. EVENT_* represent event types of the abstract event and KQ_FILTER_* represent the kevent filter type. EVENT_* can be combined while kevent.filter can only get one type.
msg269683 - (view) Author: Xiang Zhang (xiang.zhang) * (Python committer) Date: 2016-07-01 18:44
What I am saying is that EVENT_* (1, 2) are bit_masks while KQ_FILTER_* not (-1, -2, -3, -4). So you should use |= with EVENT_* and == with KQ_FILTER_*. It seems not a bug. :)
msg269686 - (view) Author: David Beazley (dabeaz) Date: 2016-07-01 19:21
If the KQ_FILTER constants aren't bitmasks, it seems that the code could be simplified to the last version then.  At the least, it would remove a few unnecessary calculations.    Again, a very minor thing (I only stumbled onto it by accident really).
msg269689 - (view) Author: Xiang Zhang (xiang.zhang) * (Python committer) Date: 2016-07-01 19:31
But EVENT_* are. If you use =, events can only be either EVENT_READ or EVENT_WRITE, not EVENT_READ & EVENT_WRITE. EVENT_* != KQ_FILTER_*.
msg269690 - (view) Author: David Beazley (dabeaz) Date: 2016-07-01 19:38
I don't see any possible way that you would ever get events = EVENT_READ | EVENT_WRITE if the flag is a single value (e.g., KQ_FILTER_READ) and the flag itself is not a bitmask.  Only one of those == tests will ever be True.  There is no need to use |=.   Unless I'm missing something.
msg269691 - (view) Author: Philip Dubé (Demur Rumed) * Date: 2016-07-01 19:42
Xiang: pause a moment to read the code being discussed. event before the |= is 0. You're saying flag must READ xor WRITE xor neither. Then only one if can be taken. Therefore events |= EVENT_* will always happen with events == 0, therefore it can be events = EVENT_*

Further inspection of the code could move the flag/events calc into the 'if key' block
msg269693 - (view) Author: Xiang Zhang (xiang.zhang) * (Python committer) Date: 2016-07-01 19:51
Oh, sorry. My focus seem to be on the wrong place. I thought David is arguing something about the constants are bitmasks or not. It's my fault. But actually the current code looks very clearly and I can tell from it that EVENT_* are bitmasks and KQ_FILTER_* are not. Also changing it is also OK and can avoid a bit calculation. Then no opinion on changing it or not.
History
Date User Action Args
2022-04-11 14:58:33adminsetgithub: 71623
2021-01-02 02:42:12dabeazsetstatus: open -> closed
stage: resolved
2016-07-01 19:51:55xiang.zhangsetmessages: + msg269693
2016-07-01 19:42:14Demur Rumedsetnosy: + Demur Rumed
messages: + msg269691
2016-07-01 19:38:52dabeazsetmessages: + msg269690
2016-07-01 19:31:30xiang.zhangsetmessages: + msg269689
2016-07-01 19:31:00berker.peksagsetnosy: + neologix
2016-07-01 19:21:32dabeazsetmessages: + msg269686
2016-07-01 18:44:14xiang.zhangsetmessages: + msg269683
2016-07-01 18:34:26xiang.zhangsetnosy: + xiang.zhang
messages: + msg269682
2016-07-01 15:33:27dabeazcreate