Skip to content

Commit fc43f35

Browse files
Merge branch 'main' into types-qualnames
2 parents bb35505 + b98d2d3 commit fc43f35

9 files changed

Lines changed: 39 additions & 123 deletions

File tree

Lib/asyncio/base_subprocess.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,6 @@ def _process_exited(self, returncode):
215215
# object. On Python 3.6, it is required to avoid a ResourceWarning.
216216
self._proc.returncode = returncode
217217
self._call(self._protocol.process_exited)
218-
for p in self._pipes.values():
219-
if p is not None:
220-
p.pipe.close()
221218

222219
self._try_finish()
223220

Lib/asyncio/events.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,7 @@ def on_fork():
836836
# Reset the loop and wakeupfd in the forked child process.
837837
if _event_loop_policy is not None:
838838
_event_loop_policy._local = BaseDefaultEventLoopPolicy._Local()
839+
_set_running_loop(None)
839840
signal.set_wakeup_fd(-1)
840841

841842
os.register_at_fork(after_in_child=on_fork)

Lib/socket.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -785,11 +785,11 @@ def getfqdn(name=''):
785785
786786
First the hostname returned by gethostbyaddr() is checked, then
787787
possibly existing aliases. In case no FQDN is available and `name`
788-
was given, it is returned unchanged. If `name` was empty or '0.0.0.0',
788+
was given, it is returned unchanged. If `name` was empty, '0.0.0.0' or '::',
789789
hostname from gethostname() is returned.
790790
"""
791791
name = name.strip()
792-
if not name or name == '0.0.0.0':
792+
if not name or name in ('0.0.0.0', '::'):
793793
name = gethostname()
794794
try:
795795
hostname, aliases, ipaddrs = gethostbyaddr(name)

Lib/test/test_asyncio/test_subprocess.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,23 @@ async def execute():
686686

687687
self.assertIsNone(self.loop.run_until_complete(execute()))
688688

689+
def test_subprocess_communicate_stdout(self):
690+
# See https://github.com/python/cpython/issues/100133
691+
async def get_command_stdout(cmd, *args):
692+
proc = await asyncio.create_subprocess_exec(
693+
cmd, *args, stdout=asyncio.subprocess.PIPE,
694+
)
695+
stdout, _ = await proc.communicate()
696+
return stdout.decode().strip()
697+
698+
async def main():
699+
outputs = [f'foo{i}' for i in range(10)]
700+
res = await asyncio.gather(*[get_command_stdout(sys.executable, '-c',
701+
f'print({out!r})') for out in outputs])
702+
self.assertEqual(res, outputs)
703+
704+
self.loop.run_until_complete(main())
705+
689706

690707
if sys.platform != 'win32':
691708
# Unix

Lib/test/test_socket.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,10 @@ def test_getaddrinfo_ipv6_basic(self):
17691769
)
17701770
self.assertEqual(sockaddr, ('ff02::1de:c0:face:8d', 1234, 0, 0))
17711771

1772+
def test_getfqdn_filter_localhost(self):
1773+
self.assertEqual(socket.getfqdn(), socket.getfqdn("0.0.0.0"))
1774+
self.assertEqual(socket.getfqdn(), socket.getfqdn("::"))
1775+
17721776
@unittest.skipUnless(socket_helper.IPV6_ENABLED, 'IPv6 required for this test.')
17731777
@unittest.skipIf(sys.platform == 'win32', 'does not work on Windows')
17741778
@unittest.skipIf(AIX, 'Symbolic scope id does not work')
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix incorrect result and delay in :func:`socket.getfqdn`. Patch by Dominic Socular.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix regression in :mod:`asyncio` where a subprocess would sometimes lose data received from pipe.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Speed up :func:`asyncio.get_running_loop` by removing redundant ``getpid`` checks. Patch by Kumar Aditya.

Modules/_asynciomodule.c

Lines changed: 12 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ typedef struct {
2323
PyTypeObject *TaskStepMethWrapper_Type;
2424
PyTypeObject *FutureType;
2525
PyTypeObject *TaskType;
26-
PyTypeObject *PyRunningLoopHolder_Type;
2726

2827
PyObject *asyncio_mod;
2928
PyObject *context_kwname;
@@ -59,8 +58,8 @@ typedef struct {
5958
/* Imports from traceback. */
6059
PyObject *traceback_extract_stack;
6160

62-
PyObject *cached_running_holder; // Borrowed ref.
63-
volatile uint64_t cached_running_holder_tsid;
61+
PyObject *cached_running_loop; // Borrowed reference
62+
volatile uint64_t cached_running_loop_tsid;
6463

6564
/* Counter for autogenerated Task names */
6665
uint64_t task_name_counter;
@@ -138,14 +137,6 @@ typedef struct {
138137
PyObject *sw_arg;
139138
} TaskStepMethWrapper;
140139

141-
typedef struct {
142-
PyObject_HEAD
143-
PyObject *rl_loop;
144-
#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
145-
pid_t rl_pid;
146-
#endif
147-
} PyRunningLoopHolder;
148-
149140

150141
#define Future_CheckExact(state, obj) Py_IS_TYPE(obj, state->FutureType)
151142
#define Task_CheckExact(state, obj) Py_IS_TYPE(obj, state->TaskType)
@@ -165,8 +156,6 @@ class _asyncio.Future "FutureObj *" "&Future_Type"
165156
/* Get FutureIter from Future */
166157
static PyObject * future_new_iter(PyObject *);
167158

168-
static PyRunningLoopHolder * new_running_loop_holder(asyncio_state *, PyObject *);
169-
170159

171160
static int
172161
_is_coroutine(asyncio_state *state, PyObject *coro)
@@ -264,11 +253,11 @@ get_running_loop(asyncio_state *state, PyObject **loop)
264253

265254
PyThreadState *ts = _PyThreadState_GET();
266255
uint64_t ts_id = PyThreadState_GetID(ts);
267-
if (state->cached_running_holder_tsid == ts_id &&
268-
state->cached_running_holder != NULL)
256+
if (state->cached_running_loop_tsid == ts_id &&
257+
state->cached_running_loop != NULL)
269258
{
270259
// Fast path, check the cache.
271-
rl = state->cached_running_holder; // borrowed
260+
rl = state->cached_running_loop;
272261
}
273262
else {
274263
PyObject *ts_dict = _PyThreadState_GetDict(ts); // borrowed
@@ -287,27 +276,16 @@ get_running_loop(asyncio_state *state, PyObject **loop)
287276
}
288277
}
289278

290-
state->cached_running_holder = rl; // borrowed
291-
state->cached_running_holder_tsid = ts_id;
279+
state->cached_running_loop = rl;
280+
state->cached_running_loop_tsid = ts_id;
292281
}
293282

294-
assert(Py_IS_TYPE(rl, state->PyRunningLoopHolder_Type));
295-
PyObject *running_loop = ((PyRunningLoopHolder *)rl)->rl_loop;
296-
297-
if (running_loop == Py_None) {
298-
goto not_found;
299-
}
300283

301-
#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
302-
/* On Windows there is no getpid, but there is also no os.fork(),
303-
so there is no need for this check.
304-
*/
305-
if (getpid() != ((PyRunningLoopHolder *)rl)->rl_pid) {
284+
if (rl == Py_None) {
306285
goto not_found;
307286
}
308-
#endif
309287

310-
*loop = Py_NewRef(running_loop);
288+
*loop = Py_NewRef(rl);
311289
return 0;
312290

313291
not_found:
@@ -335,22 +313,14 @@ set_running_loop(asyncio_state *state, PyObject *loop)
335313
PyExc_RuntimeError, "thread-local storage is not available");
336314
return -1;
337315
}
338-
339-
PyRunningLoopHolder *rl = new_running_loop_holder(state, loop);
340-
if (rl == NULL) {
341-
return -1;
342-
}
343-
344316
if (PyDict_SetItem(
345-
ts_dict, &_Py_ID(__asyncio_running_event_loop__), (PyObject *)rl) < 0)
317+
ts_dict, &_Py_ID(__asyncio_running_event_loop__), loop) < 0)
346318
{
347-
Py_DECREF(rl); // will cleanup loop & current_pid
348319
return -1;
349320
}
350-
Py_DECREF(rl);
351321

352-
state->cached_running_holder = (PyObject *)rl;
353-
state->cached_running_holder_tsid = PyThreadState_GetID(tstate);
322+
state->cached_running_loop = loop; // borrowed, kept alive by ts_dict
323+
state->cached_running_loop_tsid = PyThreadState_GetID(tstate);
354324

355325
return 0;
356326
}
@@ -3344,79 +3314,6 @@ _asyncio__leave_task_impl(PyObject *module, PyObject *loop, PyObject *task)
33443314
}
33453315

33463316

3347-
/*********************** PyRunningLoopHolder ********************/
3348-
3349-
3350-
static PyRunningLoopHolder *
3351-
new_running_loop_holder(asyncio_state *state, PyObject *loop)
3352-
{
3353-
PyRunningLoopHolder *rl = PyObject_GC_New(
3354-
PyRunningLoopHolder, state->PyRunningLoopHolder_Type);
3355-
if (rl == NULL) {
3356-
return NULL;
3357-
}
3358-
3359-
#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
3360-
rl->rl_pid = getpid();
3361-
#endif
3362-
rl->rl_loop = Py_NewRef(loop);
3363-
3364-
PyObject_GC_Track(rl);
3365-
return rl;
3366-
}
3367-
3368-
3369-
static int
3370-
PyRunningLoopHolder_clear(PyRunningLoopHolder *rl)
3371-
{
3372-
Py_CLEAR(rl->rl_loop);
3373-
return 0;
3374-
}
3375-
3376-
3377-
static int
3378-
PyRunningLoopHolder_traverse(PyRunningLoopHolder *rl, visitproc visit,
3379-
void *arg)
3380-
{
3381-
Py_VISIT(Py_TYPE(rl));
3382-
Py_VISIT(rl->rl_loop);
3383-
return 0;
3384-
}
3385-
3386-
3387-
static void
3388-
PyRunningLoopHolder_tp_dealloc(PyRunningLoopHolder *rl)
3389-
{
3390-
asyncio_state *state = get_asyncio_state_by_def((PyObject *)rl);
3391-
if (state->cached_running_holder == (PyObject *)rl) {
3392-
state->cached_running_holder = NULL;
3393-
}
3394-
PyTypeObject *tp = Py_TYPE(rl);
3395-
PyObject_GC_UnTrack(rl);
3396-
PyRunningLoopHolder_clear(rl);
3397-
PyObject_GC_Del(rl);
3398-
Py_DECREF(tp);
3399-
}
3400-
3401-
3402-
static PyType_Slot PyRunningLoopHolder_slots[] = {
3403-
{Py_tp_getattro, PyObject_GenericGetAttr},
3404-
{Py_tp_dealloc, (destructor)PyRunningLoopHolder_tp_dealloc},
3405-
{Py_tp_traverse, (traverseproc)PyRunningLoopHolder_traverse},
3406-
{Py_tp_clear, PyRunningLoopHolder_clear},
3407-
{0, NULL},
3408-
};
3409-
3410-
3411-
static PyType_Spec PyRunningLoopHolder_spec = {
3412-
.name = "_asyncio._RunningLoopHolder",
3413-
.basicsize = sizeof(PyRunningLoopHolder),
3414-
.slots = PyRunningLoopHolder_slots,
3415-
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
3416-
Py_TPFLAGS_IMMUTABLETYPE),
3417-
};
3418-
3419-
34203317
/*********************** Module **************************/
34213318

34223319

@@ -3448,7 +3345,6 @@ module_traverse(PyObject *mod, visitproc visit, void *arg)
34483345
Py_VISIT(state->TaskStepMethWrapper_Type);
34493346
Py_VISIT(state->FutureType);
34503347
Py_VISIT(state->TaskType);
3451-
Py_VISIT(state->PyRunningLoopHolder_Type);
34523348

34533349
Py_VISIT(state->asyncio_mod);
34543350
Py_VISIT(state->traceback_extract_stack);
@@ -3486,7 +3382,6 @@ module_clear(PyObject *mod)
34863382
Py_CLEAR(state->TaskStepMethWrapper_Type);
34873383
Py_CLEAR(state->FutureType);
34883384
Py_CLEAR(state->TaskType);
3489-
Py_CLEAR(state->PyRunningLoopHolder_Type);
34903385

34913386
Py_CLEAR(state->asyncio_mod);
34923387
Py_CLEAR(state->traceback_extract_stack);
@@ -3625,7 +3520,6 @@ module_exec(PyObject *mod)
36253520
} while (0)
36263521

36273522
CREATE_TYPE(mod, state->TaskStepMethWrapper_Type, &TaskStepMethWrapper_spec, NULL);
3628-
CREATE_TYPE(mod, state->PyRunningLoopHolder_Type, &PyRunningLoopHolder_spec, NULL);
36293523
CREATE_TYPE(mod, state->FutureIterType, &FutureIter_spec, NULL);
36303524
CREATE_TYPE(mod, state->FutureType, &Future_spec, NULL);
36313525
CREATE_TYPE(mod, state->TaskType, &Task_spec, state->FutureType);

0 commit comments

Comments
 (0)