From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 108106 invoked by alias); 21 Jan 2020 17:11:36 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 108092 invoked by uid 89); 21 Jan 2020 17:11:36 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-5.4 required=5.0 tests=AWL,BAYES_00,SPF_HELO_PASS,SPF_PASS autolearn=ham version=3.3.1 spammy= X-HELO: simark.ca Received: from simark.ca (HELO simark.ca) (158.69.221.121) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 21 Jan 2020 17:11:34 +0000 Received: from [172.16.0.95] (192-222-181-218.qc.cable.ebox.net [192.222.181.218]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by simark.ca (Postfix) with ESMTPSA id EAF981E5F7; Tue, 21 Jan 2020 12:11:31 -0500 (EST) Subject: Re: [PATCH v2 2/4] Unregister the last inferior from the event loop To: "Maciej W. Rozycki" Cc: Pedro Alves , gdb-patches@sourceware.org, Jim Wilson References: <2f8d9a63-db38-e5c0-d221-dd9b1e151e1b@simark.ca> From: Simon Marchi Message-ID: <323e416c-f0a9-ec14-c279-508c0245a479@simark.ca> Date: Tue, 21 Jan 2020 17:34:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.2.2 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-SW-Source: 2020-01/txt/msg00641.txt.bz2 On 2020-01-21 3:29 a.m., Maciej W. Rozycki wrote: > Hi Simon, > >>> This is because `remote_target::resume' enables the asynchronous event >>> loop, as indicated by the first `infrun: infrun_async(1)' record above, >>> and then the confirmation dialogue temporarily disables it and then >>> reenables, as indicated by the second `infrun: infrun_async(1)' record >>> above. The problem with that approach is that the reenabling also marks >>> the handler for the `infrun_async_inferior_event_token' event ready, >>> even though it was not before the temporary disabling, by calling >>> `mark_async_event_handler' on it, and that triggers the infinite loop as >>> there's no inferior anymore and consequently no event waiting that would >>> stop it. >> >> I don't understand this description. Let's assume that the second call to >> infrun_async indeed left infrun_async_inferior_event_token.ready to true. >> Then I would expect the event loop to call it once, setting the ready flag >> to false. After that, the ready being false, I don't see why the callback >> of infrun_async_inferior_event_token would get called in a loop. > > Thanks for looking into it. It's been a while however, so my memory has > become fuzzy on this. > > I have therefore gone reading through the code again and what I can see > is that in the async mode the `ready' (readiness) flag is never cleared: > see `infrun_async' and `remote_target::async', which are the only places > to call `clear_async_event_handler' and then only when the async mode is > being disabled. The ready flag is also cleared in `check_async_event_handlers`, just before invoking the callback. So I was thinking, why would the callback get called repeatedly if the ready flag is cleared just before it gets called, and there's nothing setting it back to true. The answer is probably that the busy loop is within that callback, as seen below? > On the other hand waiting for an inferior event does get disabled in > `handle_inferior_event' regardless of the readiness flag, by calling > `stop_waiting', for certain events, but not for TARGET_WAITKIND_IGNORE. > Instead for that event `prepare_to_wait' is called, which makes sense to > me because such an event does not indicate whether waiting should or > should not be disabled, and with an asynchronous target you can normally > (i.e. if not indicated by a specific event received otherwise, e.g. > TARGET_WAITKIND_EXITED) expect a further event to be received anytime. > > Does this clarify the problematic scenario to you? Ok, so if I understand, the infinite loop is this one, inside wait_for_inferior? while (1) { ... /* Now figure out what to do with the result of the result. */ handle_inferior_event (ecs); if (!ecs->wait_some_more) break; } After the remote target has been unpushed, the remaining target is probably just the "exec file" target, which does not provide a ::wait implementation, and therefore inherits default_target_wait: ptid_t default_target_wait (struct target_ops *ops, ptid_t ptid, struct target_waitstatus *status, int options) { status->kind = TARGET_WAITKIND_IGNORE; return minus_one_ptid; } And because that returns TARGET_WAITKIND_IGNORE, which results in ecs->wait_some_more getting set by handle_inferior_event/prepare_to_wait, it results in the infinite loop in wait_for_inferior. Does that look accurate? Simon