|
|
Created:
7 years, 3 months ago by jiayl Modified:
7 years, 3 months ago CC:
chromium-reviews, feature-media-reviews_chromium.org, kjellander_chromium, Niklas Enbom Base URL:
https://chromium.googlesource.com/chromium/src.git@master Visibility:
Public. |
DescriptionAdds the UserInputMonitor implementation for Windows.
BUG=274623
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=223223
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=223260
Patch Set 1 #
Total comments: 5
Patch Set 2 : #Patch Set 3 : #
Total comments: 31
Patch Set 4 : #
Total comments: 9
Patch Set 5 : #
Total comments: 6
Patch Set 6 : #
Total comments: 2
Patch Set 7 : #
Total comments: 7
Patch Set 8 : #
Total comments: 24
Patch Set 9 : #
Total comments: 3
Patch Set 10 : #
Total comments: 4
Patch Set 11 : #Patch Set 12 : #Patch Set 13 : #Patch Set 14 : #
Messages
Total messages: 51 (0 generated)
PTAL. Thanks!
https://codereview.chromium.org/23702008/diff/1/media/base/user_input_monitor... File media/base/user_input_monitor_unittest.cc (right): https://codereview.chromium.org/23702008/diff/1/media/base/user_input_monitor... media/base/user_input_monitor_unittest.cc:88: base::Thread io_thread("UserInputMonitorTestIOThread"); Do you actually need these threads? Can you just create a MessageLoop on the stack and pass it in for both UI and IO? Then use a RunLoop.RunUntilIdle() before exiting? https://codereview.chromium.org/23702008/diff/1/media/base/user_input_monitor... media/base/user_input_monitor_unittest.cc:102: #if defined(OS_MACOSX) !defined ? https://codereview.chromium.org/23702008/diff/1/media/base/user_input_monitor... File media/base/user_input_monitor_win.cc (right): https://codereview.chromium.org/23702008/diff/1/media/base/user_input_monitor... media/base/user_input_monitor_win.cc:20: // From the HID Usage Tables specification. You'll need to find mark@'s equivalent for the Windows stuff here. I don't know enough about the API to give this a thorough review.
https://codereview.chromium.org/23702008/diff/1/media/base/user_input_monitor... File media/base/user_input_monitor_unittest.cc (right): https://codereview.chromium.org/23702008/diff/1/media/base/user_input_monitor... media/base/user_input_monitor_unittest.cc:88: base::Thread io_thread("UserInputMonitorTestIOThread"); On 2013/08/29 19:02:42, DaleCurtis wrote: > Do you actually need these threads? Can you just create a MessageLoop on the > stack and pass it in for both UI and IO? Then use a RunLoop.RunUntilIdle() > before exiting? Done. https://codereview.chromium.org/23702008/diff/1/media/base/user_input_monitor... media/base/user_input_monitor_unittest.cc:102: #if defined(OS_MACOSX) On 2013/08/29 19:02:42, DaleCurtis wrote: > !defined ? Done.
Sergey/James, could you review the Windows specific code? On Thu, Aug 29, 2013 at 2:05 PM, <jiayl@chromium.org> wrote: > > https://codereview.chromium.**org/23702008/diff/1/media/** > base/user_input_monitor_**unittest.cc<https://codereview.chromium.org/23702008/diff/1/media/base/user_input_monitor_unittest.cc> > File media/base/user_input_monitor_**unittest.cc (right): > > https://codereview.chromium.**org/23702008/diff/1/media/** > base/user_input_monitor_**unittest.cc#newcode88<https://codereview.chromium.org/23702008/diff/1/media/base/user_input_monitor_unittest.cc#newcode88> > media/base/user_input_monitor_**unittest.cc:88: base::Thread > io_thread("**UserInputMonitorTestIOThread")**; > On 2013/08/29 19:02:42, DaleCurtis wrote: > >> Do you actually need these threads? Can you just create a MessageLoop >> > on the > >> stack and pass it in for both UI and IO? Then use a >> > RunLoop.RunUntilIdle() > >> before exiting? >> > > Done. > > > https://codereview.chromium.**org/23702008/diff/1/media/** > base/user_input_monitor_**unittest.cc#newcode102<https://codereview.chromium.org/23702008/diff/1/media/base/user_input_monitor_unittest.cc#newcode102> > media/base/user_input_monitor_**unittest.cc:102: #if defined(OS_MACOSX) > On 2013/08/29 19:02:42, DaleCurtis wrote: > >> !defined ? >> > > Done. > > https://codereview.chromium.**org/23702008/<https://codereview.chromium.org/2... > To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... File media/base/user_input_monitor_win.cc (right): https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:31: virtual size_t GetKeyPressCount() const OVERRIDE; nit: Suggest comment "UserInputMonitor public interface" https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:38: static int NumberOfRawInputDevices(uint8 target_events); nit: |target_events| -> |event_mask| to make it clearer that this should be a combination of EventBitMask values? Or add a comment to explain the method's usage. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:40: virtual void StartMouseMonitoring() OVERRIDE; nit: Suggest comment "UserInputMonitor private interface" to introduce this block. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:59: RAWINPUTDEVICE* GetRawInputDevices(uint8 target_events, DWORD flags); If you make this return std::vector<RAWINPUTDEVICE> then you don't end up returning a bare pointer, and you fold NummberOfRawInputDevices() into GetRawInputDevices. (If you're worried about the vector copying overhead it could return a scoped_ptr<std::vector<...> >) https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:65: // Members only accessed on the UI thread. If all the methods above are called only on the UI message loop, and all these members are called only on the UI thread, why do you need these comments? https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:101: base::Unretained(this), This will use-after-free if the StartMouseMonitoring() is called, and the caller then deletes the UserInputMonitor immediately on the calling thread, since the task will still be processed on the UI thread. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:105: StartMonitor(MOUSE_EVENT_MASK); This path will never be hit unless the caller is also on the UI thread. Better to have the PostTask, above, re-post StartMouseMonitoring(). https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:142: DCHECK(ui_task_runner_->BelongsToCurrentThread()); nit: I prefer pre-condition DCHECKs to be followed by a blank line before the rest of the method logic, for ease of readability. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:151: window_.reset(new base::win::MessageWindow()); Why re-create the window every time a new event is requested? Can't you just create the window if |events_monitored_| was empty, and call RegisterRawInputDevices() to start it receiving events? You're also never un-registering for notifications to the old window. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:165: if (window_) { Clarify that |window_| may be NULL if we failed to monitor events. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:169: // The error is harmless, ignore it. Which error? Why not trap & at least LOG_SYSERR(WARNING) it? https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:183: input_handle, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); nit: Verify that |result| is not greater than zero here, or some other -ve value than -1? https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:194: if (result == -1) { nit: See above re verifying |result| https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:230: if (RegisterRawInputDevices(devices.get(), Have you checked the semantics if e.g. two separate calls are made to RegisterRawInputDevices() that direct the same type of input to different windows, to know how this will interact w/ other users of the API in Chrome?
https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... File media/base/user_input_monitor_win.cc (right): https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:101: base::Unretained(this), On 2013/09/03 20:07:04, Wez wrote: > This will use-after-free if the StartMouseMonitoring() is called, and the caller > then deletes the UserInputMonitor immediately on the calling thread, since the > task will still be processed on the UI thread. You are right. I was assuming the caller should make sure UserInputMonitor is not deleted too early, but that seems not a good assumption. I'm going to change UserInputMonitor to ref counted. WeakPtr won't work since UserInputMonitor is destroyed and called back on different threads.
https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... File media/base/user_input_monitor_win.cc (right): https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:101: base::Unretained(this), On 2013/09/03 21:41:28, jiayl wrote: > On 2013/09/03 20:07:04, Wez wrote: > > This will use-after-free if the StartMouseMonitoring() is called, and the > caller > > then deletes the UserInputMonitor immediately on the calling thread, since the > > task will still be processed on the UI thread. > > You are right. I was assuming the caller should make sure UserInputMonitor is > not deleted too early, but that seems not a good assumption. I'm going to change > UserInputMonitor to ref counted. WeakPtr won't work since UserInputMonitor is > destroyed and called back on different threads. Isn't it invalid for a client to call StartMouseMonitoring() then delete without calling StopMouseMonitoring() ? If we can avoid ref-counting anything that'd be great.
On 2013/09/03 22:59:32, DaleCurtis wrote: > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > File media/base/user_input_monitor_win.cc (right): > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:101: base::Unretained(this), > On 2013/09/03 21:41:28, jiayl wrote: > > On 2013/09/03 20:07:04, Wez wrote: > > > This will use-after-free if the StartMouseMonitoring() is called, and the > > caller > > > then deletes the UserInputMonitor immediately on the calling thread, since > the > > > task will still be processed on the UI thread. > > > > You are right. I was assuming the caller should make sure UserInputMonitor is > > not deleted too early, but that seems not a good assumption. I'm going to > change > > UserInputMonitor to ref counted. WeakPtr won't work since UserInputMonitor is > > destroyed and called back on different threads. > > Isn't it invalid for a client to call StartMouseMonitoring() then delete without > calling StopMouseMonitoring() ? If we can avoid ref-counting anything that'd be > great. That's true. But if StopMouseMonitoring is called right before UserInputMonitor, the queued async events on the UI thread may still call back to the destroyed UserInputMonitor.
PTAL. sky, could you review the change in browser_main_loop.h? https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... File media/base/user_input_monitor_win.cc (right): https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:31: virtual size_t GetKeyPressCount() const OVERRIDE; On 2013/09/03 20:07:04, Wez wrote: > nit: Suggest comment "UserInputMonitor public interface" Done. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:38: static int NumberOfRawInputDevices(uint8 target_events); On 2013/09/03 20:07:04, Wez wrote: > nit: |target_events| -> |event_mask| to make it clearer that this should be a > combination of EventBitMask values? Or add a comment to explain the method's > usage. Done. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:40: virtual void StartMouseMonitoring() OVERRIDE; On 2013/09/03 20:07:04, Wez wrote: > nit: Suggest comment "UserInputMonitor private interface" to introduce this > block. Done. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:40: virtual void StartMouseMonitoring() OVERRIDE; On 2013/09/03 20:07:04, Wez wrote: > nit: Suggest comment "UserInputMonitor private interface" to introduce this > block. Done. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:59: RAWINPUTDEVICE* GetRawInputDevices(uint8 target_events, DWORD flags); On 2013/09/03 20:07:04, Wez wrote: > If you make this return std::vector<RAWINPUTDEVICE> then you don't end up > returning a bare pointer, and you fold NummberOfRawInputDevices() into > GetRawInputDevices. > > (If you're worried about the vector copying overhead it could return a > scoped_ptr<std::vector<...> >) Done. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:65: // Members only accessed on the UI thread. On 2013/09/03 20:07:04, Wez wrote: > If all the methods above are called only on the UI message loop, and all these > members are called only on the UI thread, why do you need these comments? Done. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:101: base::Unretained(this), On 2013/09/03 20:07:04, Wez wrote: > This will use-after-free if the StartMouseMonitoring() is called, and the caller > then deletes the UserInputMonitor immediately on the calling thread, since the > task will still be processed on the UI thread. Done. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:105: StartMonitor(MOUSE_EVENT_MASK); On 2013/09/03 20:07:04, Wez wrote: > This path will never be hit unless the caller is also on the UI thread. Better > to have the PostTask, above, re-post StartMouseMonitoring(). Done. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:142: DCHECK(ui_task_runner_->BelongsToCurrentThread()); On 2013/09/03 20:07:04, Wez wrote: > nit: I prefer pre-condition DCHECKs to be followed by a blank line before the > rest of the method logic, for ease of readability. Done. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:151: window_.reset(new base::win::MessageWindow()); On 2013/09/03 20:07:04, Wez wrote: > Why re-create the window every time a new event is requested? Can't you just > create the window if |events_monitored_| was empty, and call > RegisterRawInputDevices() to start it receiving events? > > You're also never un-registering for notifications to the old window. Done. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:165: if (window_) { On 2013/09/03 20:07:04, Wez wrote: > Clarify that |window_| may be NULL if we failed to monitor events. Done. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:169: // The error is harmless, ignore it. On 2013/09/03 20:07:04, Wez wrote: > Which error? Why not trap & at least LOG_SYSERR(WARNING) it? Done. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:183: input_handle, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); On 2013/09/03 20:07:04, Wez wrote: > nit: Verify that |result| is not greater than zero here, or some other -ve value > than -1? Done. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:194: if (result == -1) { On 2013/09/03 20:07:04, Wez wrote: > nit: See above re verifying |result| Done. https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:230: if (RegisterRawInputDevices(devices.get(), On 2013/09/03 20:07:04, Wez wrote: > Have you checked the semantics if e.g. two separate calls are made to > RegisterRawInputDevices() that direct the same type of input to different > windows, to know how this will interact w/ other users of the API in Chrome? Hmm...I verified that only one window will receive the event if multiple ones are registered. Chrome has no other callers though.
On 2013/09/03 23:01:51, jiayl wrote: > On 2013/09/03 22:59:32, DaleCurtis wrote: > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > File media/base/user_input_monitor_win.cc (right): > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:101: base::Unretained(this), > > On 2013/09/03 21:41:28, jiayl wrote: > > > On 2013/09/03 20:07:04, Wez wrote: > > > > This will use-after-free if the StartMouseMonitoring() is called, and the > > > caller > > > > then deletes the UserInputMonitor immediately on the calling thread, since > > the > > > > task will still be processed on the UI thread. > > > > > > You are right. I was assuming the caller should make sure UserInputMonitor > is > > > not deleted too early, but that seems not a good assumption. I'm going to > > change > > > UserInputMonitor to ref counted. WeakPtr won't work since UserInputMonitor > is > > > destroyed and called back on different threads. > > > > Isn't it invalid for a client to call StartMouseMonitoring() then delete > without > > calling StopMouseMonitoring() ? If we can avoid ref-counting anything that'd > be > > great. > > That's true. But if StopMouseMonitoring is called right before UserInputMonitor, > the queued async events on the UI thread may still call back to the destroyed > UserInputMonitor. Not if those events were bound to WeakPtrs to the UserInputMonitor. :)
On 2013/09/03 23:44:12, jiayl wrote: > PTAL. > > sky, could you review the change in browser_main_loop.h? > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > File media/base/user_input_monitor_win.cc (right): > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:31: virtual size_t GetKeyPressCount() const > OVERRIDE; > On 2013/09/03 20:07:04, Wez wrote: > > nit: Suggest comment "UserInputMonitor public interface" > > Done. > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:38: static int > NumberOfRawInputDevices(uint8 target_events); > On 2013/09/03 20:07:04, Wez wrote: > > nit: |target_events| -> |event_mask| to make it clearer that this should be a > > combination of EventBitMask values? Or add a comment to explain the method's > > usage. > > Done. > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:40: virtual void StartMouseMonitoring() > OVERRIDE; > On 2013/09/03 20:07:04, Wez wrote: > > nit: Suggest comment "UserInputMonitor private interface" to introduce this > > block. > > Done. > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:40: virtual void StartMouseMonitoring() > OVERRIDE; > On 2013/09/03 20:07:04, Wez wrote: > > nit: Suggest comment "UserInputMonitor private interface" to introduce this > > block. > > Done. > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:59: RAWINPUTDEVICE* > GetRawInputDevices(uint8 target_events, DWORD flags); > On 2013/09/03 20:07:04, Wez wrote: > > If you make this return std::vector<RAWINPUTDEVICE> then you don't end up > > returning a bare pointer, and you fold NummberOfRawInputDevices() into > > GetRawInputDevices. > > > > (If you're worried about the vector copying overhead it could return a > > scoped_ptr<std::vector<...> >) > > Done. > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:65: // Members only accessed on the UI > thread. > On 2013/09/03 20:07:04, Wez wrote: > > If all the methods above are called only on the UI message loop, and all these > > members are called only on the UI thread, why do you need these comments? > > Done. > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:101: base::Unretained(this), > On 2013/09/03 20:07:04, Wez wrote: > > This will use-after-free if the StartMouseMonitoring() is called, and the > caller > > then deletes the UserInputMonitor immediately on the calling thread, since the > > task will still be processed on the UI thread. > > Done. > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:105: StartMonitor(MOUSE_EVENT_MASK); > On 2013/09/03 20:07:04, Wez wrote: > > This path will never be hit unless the caller is also on the UI thread. Better > > to have the PostTask, above, re-post StartMouseMonitoring(). > > Done. > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:142: > DCHECK(ui_task_runner_->BelongsToCurrentThread()); > On 2013/09/03 20:07:04, Wez wrote: > > nit: I prefer pre-condition DCHECKs to be followed by a blank line before the > > rest of the method logic, for ease of readability. > > Done. > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:151: window_.reset(new > base::win::MessageWindow()); > On 2013/09/03 20:07:04, Wez wrote: > > Why re-create the window every time a new event is requested? Can't you just > > create the window if |events_monitored_| was empty, and call > > RegisterRawInputDevices() to start it receiving events? > > > > You're also never un-registering for notifications to the old window. > > Done. > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:165: if (window_) { > On 2013/09/03 20:07:04, Wez wrote: > > Clarify that |window_| may be NULL if we failed to monitor events. > > Done. > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:169: // The error is harmless, ignore it. > On 2013/09/03 20:07:04, Wez wrote: > > Which error? Why not trap & at least LOG_SYSERR(WARNING) it? > > Done. > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:183: input_handle, RID_INPUT, NULL, &size, > sizeof(RAWINPUTHEADER)); > On 2013/09/03 20:07:04, Wez wrote: > > nit: Verify that |result| is not greater than zero here, or some other -ve > value > > than -1? > > Done. > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:194: if (result == -1) { > On 2013/09/03 20:07:04, Wez wrote: > > nit: See above re verifying |result| > > Done. > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > media/base/user_input_monitor_win.cc:230: if > (RegisterRawInputDevices(devices.get(), > On 2013/09/03 20:07:04, Wez wrote: > > Have you checked the semantics if e.g. two separate calls are made to > > RegisterRawInputDevices() that direct the same type of input to different > > windows, to know how this will interact w/ other users of the API in Chrome? > Hmm...I verified that only one window will receive the event if multiple ones > are registered. Chrome has no other callers though. Do you only create a single UserInputMonitor no matter how many capture streams are active, then?
On 2013/09/04 00:08:51, Wez wrote: > On 2013/09/03 23:44:12, jiayl wrote: > > PTAL. > > > > sky, could you review the change in browser_main_loop.h? > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > File media/base/user_input_monitor_win.cc (right): > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:31: virtual size_t GetKeyPressCount() > const > > OVERRIDE; > > On 2013/09/03 20:07:04, Wez wrote: > > > nit: Suggest comment "UserInputMonitor public interface" > > > > Done. > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:38: static int > > NumberOfRawInputDevices(uint8 target_events); > > On 2013/09/03 20:07:04, Wez wrote: > > > nit: |target_events| -> |event_mask| to make it clearer that this should be > a > > > combination of EventBitMask values? Or add a comment to explain the method's > > > usage. > > > > Done. > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:40: virtual void StartMouseMonitoring() > > OVERRIDE; > > On 2013/09/03 20:07:04, Wez wrote: > > > nit: Suggest comment "UserInputMonitor private interface" to introduce this > > > block. > > > > Done. > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:40: virtual void StartMouseMonitoring() > > OVERRIDE; > > On 2013/09/03 20:07:04, Wez wrote: > > > nit: Suggest comment "UserInputMonitor private interface" to introduce this > > > block. > > > > Done. > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:59: RAWINPUTDEVICE* > > GetRawInputDevices(uint8 target_events, DWORD flags); > > On 2013/09/03 20:07:04, Wez wrote: > > > If you make this return std::vector<RAWINPUTDEVICE> then you don't end up > > > returning a bare pointer, and you fold NummberOfRawInputDevices() into > > > GetRawInputDevices. > > > > > > (If you're worried about the vector copying overhead it could return a > > > scoped_ptr<std::vector<...> >) > > > > Done. > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:65: // Members only accessed on the UI > > thread. > > On 2013/09/03 20:07:04, Wez wrote: > > > If all the methods above are called only on the UI message loop, and all > these > > > members are called only on the UI thread, why do you need these comments? > > > > Done. > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:101: base::Unretained(this), > > On 2013/09/03 20:07:04, Wez wrote: > > > This will use-after-free if the StartMouseMonitoring() is called, and the > > caller > > > then deletes the UserInputMonitor immediately on the calling thread, since > the > > > task will still be processed on the UI thread. > > > > Done. > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:105: StartMonitor(MOUSE_EVENT_MASK); > > On 2013/09/03 20:07:04, Wez wrote: > > > This path will never be hit unless the caller is also on the UI thread. > Better > > > to have the PostTask, above, re-post StartMouseMonitoring(). > > > > Done. > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:142: > > DCHECK(ui_task_runner_->BelongsToCurrentThread()); > > On 2013/09/03 20:07:04, Wez wrote: > > > nit: I prefer pre-condition DCHECKs to be followed by a blank line before > the > > > rest of the method logic, for ease of readability. > > > > Done. > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:151: window_.reset(new > > base::win::MessageWindow()); > > On 2013/09/03 20:07:04, Wez wrote: > > > Why re-create the window every time a new event is requested? Can't you just > > > create the window if |events_monitored_| was empty, and call > > > RegisterRawInputDevices() to start it receiving events? > > > > > > You're also never un-registering for notifications to the old window. > > > > Done. > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:165: if (window_) { > > On 2013/09/03 20:07:04, Wez wrote: > > > Clarify that |window_| may be NULL if we failed to monitor events. > > > > Done. > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:169: // The error is harmless, ignore it. > > On 2013/09/03 20:07:04, Wez wrote: > > > Which error? Why not trap & at least LOG_SYSERR(WARNING) it? > > > > Done. > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:183: input_handle, RID_INPUT, NULL, > &size, > > sizeof(RAWINPUTHEADER)); > > On 2013/09/03 20:07:04, Wez wrote: > > > nit: Verify that |result| is not greater than zero here, or some other -ve > > value > > > than -1? > > > > Done. > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:194: if (result == -1) { > > On 2013/09/03 20:07:04, Wez wrote: > > > nit: See above re verifying |result| > > > > Done. > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > media/base/user_input_monitor_win.cc:230: if > > (RegisterRawInputDevices(devices.get(), > > On 2013/09/03 20:07:04, Wez wrote: > > > Have you checked the semantics if e.g. two separate calls are made to > > > RegisterRawInputDevices() that direct the same type of input to different > > > windows, to know how this will interact w/ other users of the API in Chrome? > > Hmm...I verified that only one window will receive the event if multiple ones > > are registered. Chrome has no other callers though. > > Do you only create a single UserInputMonitor no matter how many capture streams > are active, then? Correct.
On 2013/09/04 00:07:51, Wez wrote: > On 2013/09/03 23:01:51, jiayl wrote: > > On 2013/09/03 22:59:32, DaleCurtis wrote: > > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > > File media/base/user_input_monitor_win.cc (right): > > > > > > > > > https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_moni... > > > media/base/user_input_monitor_win.cc:101: base::Unretained(this), > > > On 2013/09/03 21:41:28, jiayl wrote: > > > > On 2013/09/03 20:07:04, Wez wrote: > > > > > This will use-after-free if the StartMouseMonitoring() is called, and > the > > > > caller > > > > > then deletes the UserInputMonitor immediately on the calling thread, > since > > > the > > > > > task will still be processed on the UI thread. > > > > > > > > You are right. I was assuming the caller should make sure UserInputMonitor > > is > > > > not deleted too early, but that seems not a good assumption. I'm going to > > > change > > > > UserInputMonitor to ref counted. WeakPtr won't work since UserInputMonitor > > is > > > > destroyed and called back on different threads. > > > > > > Isn't it invalid for a client to call StartMouseMonitoring() then delete > > without > > > calling StopMouseMonitoring() ? If we can avoid ref-counting anything that'd > > be > > > great. > > > > That's true. But if StopMouseMonitoring is called right before > UserInputMonitor, > > the queued async events on the UI thread may still call back to the destroyed > > UserInputMonitor. > > Not if those events were bound to WeakPtrs to the UserInputMonitor. :) But the WeakPtrs need to be deref'd on the callback thread while UserInputMonitor is destroyed on the main thread, which means WeakPtrs are invalidated and deref'd on different threads.
On 3 September 2013 17:12, <jiayl@chromium.org> wrote: > On 2013/09/04 00:07:51, Wez wrote: > >> On 2013/09/03 23:01:51, jiayl wrote: >> > On 2013/09/03 22:59:32, DaleCurtis wrote: >> > > >> > >> > > https://codereview.chromium.**org/23702008/diff/8001/media/** > base/user_input_monitor_win.cc<https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_monitor_win.cc> > >> > > File media/base/user_input_monitor_**win.cc (right): >> > > >> > > >> > >> > > https://codereview.chromium.**org/23702008/diff/8001/media/** > base/user_input_monitor_win.**cc#newcode101<https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_monitor_win.cc#newcode101> > >> > > media/base/user_input_monitor_**win.cc:101: base::Unretained(this), >> >> > > On 2013/09/03 21:41:28, jiayl wrote: >> > > > On 2013/09/03 20:07:04, Wez wrote: >> > > > > This will use-after-free if the StartMouseMonitoring() is called, >> and >> the >> > > > caller >> > > > > then deletes the UserInputMonitor immediately on the calling >> thread, >> since >> > > the >> > > > > task will still be processed on the UI thread. >> > > > >> > > > You are right. I was assuming the caller should make sure >> > UserInputMonitor > >> > is >> > > > not deleted too early, but that seems not a good assumption. I'm >> going >> > to > >> > > change >> > > > UserInputMonitor to ref counted. WeakPtr won't work since >> > UserInputMonitor > >> > is >> > > > destroyed and called back on different threads. >> > > >> > > Isn't it invalid for a client to call StartMouseMonitoring() then >> delete >> > without >> > > calling StopMouseMonitoring() ? If we can avoid ref-counting anything >> > that'd > >> > be >> > > great. >> > >> > That's true. But if StopMouseMonitoring is called right before >> UserInputMonitor, >> > the queued async events on the UI thread may still call back to the >> > destroyed > >> > UserInputMonitor. >> > > Not if those events were bound to WeakPtrs to the UserInputMonitor. :) >> > > But the WeakPtrs need to be deref'd on the callback thread while > UserInputMonitor is destroyed on the main thread, which means WeakPtrs are > invalidated and deref'd on different threads. Which are the "callback" and "main" threads wrt this CL? You mean the |ui_task_runner| and calling threads? Looking at UserInputMonitor's implementation, I'd assumed you must punt the mouse notifications back to the calling thread for dispatch, to avoid a race between notifications and calls to RemoveMouseListener(), which case you;d be dereferencing the WeakPtr on the caller thread, which would work. It looks like you're instead relying on locking around the observer-list modifications, and observer notifications - are you sure that's a good idea? It means that one badly-behaved observer can indirectly block the UI thread. :( > > https://codereview.chromium.**org/23702008/<https://codereview.chromium.org/2... > To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
On 2013/09/04 00:21:23, Wez wrote: > On 3 September 2013 17:12, <mailto:jiayl@chromium.org> wrote: > > > On 2013/09/04 00:07:51, Wez wrote: > > > >> On 2013/09/03 23:01:51, jiayl wrote: > >> > On 2013/09/03 22:59:32, DaleCurtis wrote: > >> > > > >> > > >> > > > > https://codereview.chromium.**org/23702008/diff/8001/media/** > > > base/user_input_monitor_win.cc<https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_monitor_win.cc> > > > >> > > File media/base/user_input_monitor_**win.cc (right): > >> > > > >> > > > >> > > >> > > > > https://codereview.chromium.**org/23702008/diff/8001/media/** > > > base/user_input_monitor_win.**cc#newcode101<https://codereview.chromium.org/23702008/diff/8001/media/base/user_input_monitor_win.cc#newcode101> > > > >> > > media/base/user_input_monitor_**win.cc:101: base::Unretained(this), > >> > >> > > On 2013/09/03 21:41:28, jiayl wrote: > >> > > > On 2013/09/03 20:07:04, Wez wrote: > >> > > > > This will use-after-free if the StartMouseMonitoring() is called, > >> and > >> the > >> > > > caller > >> > > > > then deletes the UserInputMonitor immediately on the calling > >> thread, > >> since > >> > > the > >> > > > > task will still be processed on the UI thread. > >> > > > > >> > > > You are right. I was assuming the caller should make sure > >> > > UserInputMonitor > > > >> > is > >> > > > not deleted too early, but that seems not a good assumption. I'm > >> going > >> > > to > > > >> > > change > >> > > > UserInputMonitor to ref counted. WeakPtr won't work since > >> > > UserInputMonitor > > > >> > is > >> > > > destroyed and called back on different threads. > >> > > > >> > > Isn't it invalid for a client to call StartMouseMonitoring() then > >> delete > >> > without > >> > > calling StopMouseMonitoring() ? If we can avoid ref-counting anything > >> > > that'd > > > >> > be > >> > > great. > >> > > >> > That's true. But if StopMouseMonitoring is called right before > >> UserInputMonitor, > >> > the queued async events on the UI thread may still call back to the > >> > > destroyed > > > >> > UserInputMonitor. > >> > > > > Not if those events were bound to WeakPtrs to the UserInputMonitor. :) > >> > > > > But the WeakPtrs need to be deref'd on the callback thread while > > UserInputMonitor is destroyed on the main thread, which means WeakPtrs are > > invalidated and deref'd on different threads. > > > Which are the "callback" and "main" threads wrt this CL? You mean the > |ui_task_runner| and calling threads? > > Looking at UserInputMonitor's implementation, I'd assumed you must punt the > mouse notifications back to the calling thread for dispatch, to avoid a > race between notifications and calls to RemoveMouseListener(), which case > you;d be dereferencing the WeakPtr on the caller thread, which would work. > > It looks like you're instead relying on locking around the observer-list > modifications, and observer notifications - are you sure that's a good > idea? It means that one badly-behaved observer can indirectly block the UI > thread. :( > > > > > > > https://codereview.chromium.**org/23702008/%3Chttps://codereview.chromium.org...> > > > > To unsubscribe from this group and stop receiving emails from it, send an email > to mailto:chromium-reviews+unsubscribe@chromium.org. But AddMouseListener/RemoveMouseListener can be called on any thread. Which thread should the callback be dispatched to? Plus the calling thread of Add/RemoveListener is not the same thread that creates/destroys UserInputMonitor, which means there is still a problem in using WeakPtr.
LGTM
Looks like there are some races - see my comments. I already suggested in previous CLs to use ObserverListThreadSafe - it will help to avoid the problems Wez pointed at and also guarantees that notifications are delivered on the same thread on which listener is registered. You can use it with a locked listeners counter to detect when to start/stop monitoring. I also don't like that you are making UserInputMonitor ref-counted. You can avoid it easily by using a "Core" object. It can be ref-counted, e.g. as in remoting::LocalInputMonitorLinux, but if you destroy on the thread on which events are received then it won't need to be ref-counted. https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_mon... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_mon... media/base/user_input_monitor_linux.cc:138: if (!io_task_runner_->BelongsToCurrentThread()) { There is potential race between StartKeyboardMonitoring() and StopKeyboardMonitoring(). If StopKeyboardMonitoring() is called on a thread other than the IO thread and then StartKeyboardMonitoring() is called the IO immediately after that then monitoring will be started and then stopped on the IO thread, while it should be stopped first and then started. I think you can avoid it by always posting a task to call StopMonitor(). https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_mon... File media/base/user_input_monitor_win.cc (right): https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_mon... media/base/user_input_monitor_win.cc:114: if (!ui_task_runner_->BelongsToCurrentThread()) { There is a same race as in Linux version of this code. Just post a task for StopMonitor()? https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_mon... media/base/user_input_monitor_win.cc:207: ? ui::ET_KEY_RELEASED nit: operators should not be wrapped. ? goes on the previous line. https://codereview.chromium.org/23702008/diff/20001/media/media.gyp File media/media.gyp (right): https://codereview.chromium.org/23702008/diff/20001/media/media.gyp#newcode884 media/media.gyp:884: 'sources!': [ indentation
On Wed, Sep 4, 2013 at 11:40 AM, <sergeyu@chromium.org> wrote: > Looks like there are some races - see my comments. > > I already suggested in previous CLs to use ObserverListThreadSafe - it > will help > to avoid the problems Wez pointed at and also guarantees that > notifications are > delivered on the same thread on which listener is registered. You can use > it > with a locked listeners counter to detect when to start/stop monitoring. > > I also don't like that you are making UserInputMonitor ref-counted. You can > avoid it easily by using a "Core" object. It can be ref-counted, e.g. as in > remoting::**LocalInputMonitorLinux, but if you destroy on the thread on > which > events are received then it won't need to be ref-counted. > OberserListThreadSafe is also implemented through locks ( https://code.google.com/p/chromium/codesearch#chromium/src/base/observer_list...), so will not solve the issue wez pointed out. I don't see a way to get rid of the lock; but I can remove the ref-counting of UserInputMonitor by posting the callback to the thread that creates/destroys UserInputMonior, i.e. the browser UI thread, to make WeakPtr valid to use. How about that? > > https://codereview.chromium.**org/23702008/diff/20001/media/** > base/user_input_monitor_linux.**cc<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_linux.cc> > File media/base/user_input_monitor_**linux.cc (right): > > https://codereview.chromium.**org/23702008/diff/20001/media/** > base/user_input_monitor_linux.**cc#newcode138<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_linux.cc#newcode138> > media/base/user_input_monitor_**linux.cc:138: if > (!io_task_runner_->**BelongsToCurrentThread()) { > There is potential race between StartKeyboardMonitoring() and > StopKeyboardMonitoring(). If StopKeyboardMonitoring() is called on a > thread other than the IO thread and then StartKeyboardMonitoring() is > called the IO immediately after that then monitoring will be started and > then stopped on the IO thread, while it should be stopped first and then > started. I think you can avoid it by always posting a task to call > StopMonitor(). > > https://codereview.chromium.**org/23702008/diff/20001/media/** > base/user_input_monitor_win.cc<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc> > File media/base/user_input_monitor_**win.cc (right): > > https://codereview.chromium.**org/23702008/diff/20001/media/** > base/user_input_monitor_win.**cc#newcode114<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc#newcode114> > media/base/user_input_monitor_**win.cc:114: if > (!ui_task_runner_->**BelongsToCurrentThread()) { > There is a same race as in Linux version of this code. Just post a task > for StopMonitor()? > > https://codereview.chromium.**org/23702008/diff/20001/media/** > base/user_input_monitor_win.**cc#newcode207<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc#newcode207> > media/base/user_input_monitor_**win.cc:207: ? ui::ET_KEY_RELEASED > nit: operators should not be wrapped. ? goes on the previous line. > > https://codereview.chromium.**org/23702008/diff/20001/media/**media.gyp<https... > File media/media.gyp (right): > > https://codereview.chromium.**org/23702008/diff/20001/media/** > media.gyp#newcode884<https://codereview.chromium.org/23702008/diff/20001/media/media.gyp#newcode884> > media/media.gyp:884: 'sources!': [ > indentation > > https://codereview.chromium.**org/23702008/<https://codereview.chromium.org/2... > To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
On Wed, Sep 4, 2013 at 11:49 AM, Jiayang Liu <jiayl@chromium.org> wrote: > > On Wed, Sep 4, 2013 at 11:40 AM, <sergeyu@chromium.org> wrote: > >> Looks like there are some races - see my comments. >> >> I already suggested in previous CLs to use ObserverListThreadSafe - it >> will help >> to avoid the problems Wez pointed at and also guarantees that >> notifications are >> delivered on the same thread on which listener is registered. You can use >> it >> with a locked listeners counter to detect when to start/stop monitoring. >> >> I also don't like that you are making UserInputMonitor ref-counted. You >> can >> avoid it easily by using a "Core" object. It can be ref-counted, e.g. as >> in >> remoting::**LocalInputMonitorLinux, but if you destroy on the thread on >> which >> events are received then it won't need to be ref-counted. >> > > > OberserListThreadSafe is also implemented through locks ( > https://code.google.com/p/chromium/codesearch#chromium/src/base/observer_list...), > so will not solve the issue wez pointed out. > OberserListThreadSafe holds a lock only to post a task. It always releases the lock before calling observers. > > I don't see a way to get rid of the lock; but I can remove the > ref-counting of UserInputMonitor by posting the callback to the thread that > creates/destroys UserInputMonior, i.e. the browser UI thread, to make > WeakPtr valid to use. > > How about that? > >> >> > https://codereview.chromium.**org/23702008/diff/20001/media/** >> base/user_input_monitor_linux.**cc<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_linux.cc> >> File media/base/user_input_monitor_**linux.cc (right): >> >> https://codereview.chromium.**org/23702008/diff/20001/media/** >> base/user_input_monitor_linux.**cc#newcode138<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_linux.cc#newcode138> >> media/base/user_input_monitor_**linux.cc:138: if >> (!io_task_runner_->**BelongsToCurrentThread()) { >> There is potential race between StartKeyboardMonitoring() and >> StopKeyboardMonitoring(). If StopKeyboardMonitoring() is called on a >> thread other than the IO thread and then StartKeyboardMonitoring() is >> called the IO immediately after that then monitoring will be started and >> then stopped on the IO thread, while it should be stopped first and then >> started. I think you can avoid it by always posting a task to call >> StopMonitor(). >> >> https://codereview.chromium.**org/23702008/diff/20001/media/** >> base/user_input_monitor_win.cc<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc> >> File media/base/user_input_monitor_**win.cc (right): >> >> https://codereview.chromium.**org/23702008/diff/20001/media/** >> base/user_input_monitor_win.**cc#newcode114<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc#newcode114> >> media/base/user_input_monitor_**win.cc:114: if >> (!ui_task_runner_->**BelongsToCurrentThread()) { >> There is a same race as in Linux version of this code. Just post a task >> for StopMonitor()? >> >> https://codereview.chromium.**org/23702008/diff/20001/media/** >> base/user_input_monitor_win.**cc#newcode207<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc#newcode207> >> media/base/user_input_monitor_**win.cc:207: ? ui::ET_KEY_RELEASED >> nit: operators should not be wrapped. ? goes on the previous line. >> >> https://codereview.chromium.**org/23702008/diff/20001/media/**media.gyp<https... >> File media/media.gyp (right): >> >> https://codereview.chromium.**org/23702008/diff/20001/media/** >> media.gyp#newcode884<https://codereview.chromium.org/23702008/diff/20001/media/media.gyp#newcode884> >> media/media.gyp:884: 'sources!': [ >> indentation >> >> https://codereview.chromium.**org/23702008/<https://codereview.chromium.org/2... >> > > To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
On Wed, Sep 4, 2013 at 11:53 AM, Sergey Ulanov <sergeyu@chromium.org> wrote: > > On Wed, Sep 4, 2013 at 11:49 AM, Jiayang Liu <jiayl@chromium.org> wrote: > >> >> On Wed, Sep 4, 2013 at 11:40 AM, <sergeyu@chromium.org> wrote: >> >>> Looks like there are some races - see my comments. >>> >>> I already suggested in previous CLs to use ObserverListThreadSafe - it >>> will help >>> to avoid the problems Wez pointed at and also guarantees that >>> notifications are >>> delivered on the same thread on which listener is registered. You can >>> use it >>> with a locked listeners counter to detect when to start/stop monitoring. >>> >>> I also don't like that you are making UserInputMonitor ref-counted. You >>> can >>> avoid it easily by using a "Core" object. It can be ref-counted, e.g. as >>> in >>> remoting::**LocalInputMonitorLinux, but if you destroy on the thread on >>> which >>> events are received then it won't need to be ref-counted. >>> >> >> >> OberserListThreadSafe is also implemented through locks ( >> https://code.google.com/p/chromium/codesearch#chromium/src/base/observer_list...), >> so will not solve the issue wez pointed out. >> > > OberserListThreadSafe holds a lock only to post a task. It always releases > the lock before calling observers. > > Ah, I see. I'll fix that then. :) Thanks! > >> I don't see a way to get rid of the lock; but I can remove the >> ref-counting of UserInputMonitor by posting the callback to the thread that >> creates/destroys UserInputMonior, i.e. the browser UI thread, to make >> WeakPtr valid to use. >> >> How about that? >> >>> >>> >> https://codereview.chromium.**org/23702008/diff/20001/media/** >>> base/user_input_monitor_linux.**cc<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_linux.cc> >>> File media/base/user_input_monitor_**linux.cc (right): >>> >>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>> base/user_input_monitor_linux.**cc#newcode138<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_linux.cc#newcode138> >>> media/base/user_input_monitor_**linux.cc:138: if >>> (!io_task_runner_->**BelongsToCurrentThread()) { >>> There is potential race between StartKeyboardMonitoring() and >>> StopKeyboardMonitoring(). If StopKeyboardMonitoring() is called on a >>> thread other than the IO thread and then StartKeyboardMonitoring() is >>> called the IO immediately after that then monitoring will be started and >>> then stopped on the IO thread, while it should be stopped first and then >>> started. I think you can avoid it by always posting a task to call >>> StopMonitor(). >>> >>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>> base/user_input_monitor_win.cc<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc> >>> File media/base/user_input_monitor_**win.cc (right): >>> >>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>> base/user_input_monitor_win.**cc#newcode114<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc#newcode114> >>> media/base/user_input_monitor_**win.cc:114: if >>> (!ui_task_runner_->**BelongsToCurrentThread()) { >>> There is a same race as in Linux version of this code. Just post a task >>> for StopMonitor()? >>> >>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>> base/user_input_monitor_win.**cc#newcode207<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc#newcode207> >>> media/base/user_input_monitor_**win.cc:207: ? ui::ET_KEY_RELEASED >>> nit: operators should not be wrapped. ? goes on the previous line. >>> >>> https://codereview.chromium.**org/23702008/diff/20001/media/**media.gyp<https... >>> File media/media.gyp (right): >>> >>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>> media.gyp#newcode884<https://codereview.chromium.org/23702008/diff/20001/media/media.gyp#newcode884> >>> media/media.gyp:884: 'sources!': [ >>> indentation >>> >>> https://codereview.chromium.**org/23702008/<https://codereview.chromium.org/2... >>> >> >> > To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
I'm planning to make this change to remove the assumption that UserInputMonitor has to outlive the UI/IO browser threads. Please let me know what you think. I'll have a UserInputMonitorWrapper class to handle the creation and destruction of UserInputMonitor: class UserInputMonitorWrapper { public: UserInputMonitorWrapper(io_task_runner, ui_task_runner); ~UserInputMonitorWrapper(); UserInputMonitor* user_input_monitor() { return monitor_; } private: UserInputMonitor* monitor_; } The implementation of UserInputMonitorWrapper will be platform specifc, for example on Linux: UserInputMonitorWrapper::UserInputMonitorWrapper (...) { monitor_ = new UserInputMonitorLinux(io_task_runner); } // Dispatch to the IO thread to delete |monitor_|. UserInputMonitorWrapper::~UserInputMonitorWrapper() { monitor_->io_task_runner()->PostTask( &UserInputMonitorLinux::Shutdown, base::Owned(monitor_)); monitor_ = NULL; } Then UserInputMonitorLinux can use WeakPtr for posting tasks to the IO thread since it will be destructed on the IO thread. It doesn't matter if the io_task_runner is not running when the wrapper is destructed since base::Owned will make sure |monitor_| is not leaked. UserInputMonitorLinux::Shutdown does not need to anything except checking monitoring has been stopped. On Wed, Sep 4, 2013 at 11:56 AM, Jiayang Liu <jiayl@chromium.org> wrote: > > > > On Wed, Sep 4, 2013 at 11:53 AM, Sergey Ulanov <sergeyu@chromium.org>wrote: > >> >> On Wed, Sep 4, 2013 at 11:49 AM, Jiayang Liu <jiayl@chromium.org> wrote: >> >>> >>> On Wed, Sep 4, 2013 at 11:40 AM, <sergeyu@chromium.org> wrote: >>> >>>> Looks like there are some races - see my comments. >>>> >>>> I already suggested in previous CLs to use ObserverListThreadSafe - it >>>> will help >>>> to avoid the problems Wez pointed at and also guarantees that >>>> notifications are >>>> delivered on the same thread on which listener is registered. You can >>>> use it >>>> with a locked listeners counter to detect when to start/stop monitoring. >>>> >>>> I also don't like that you are making UserInputMonitor ref-counted. You >>>> can >>>> avoid it easily by using a "Core" object. It can be ref-counted, e.g. >>>> as in >>>> remoting::**LocalInputMonitorLinux, but if you destroy on the thread >>>> on which >>>> events are received then it won't need to be ref-counted. >>>> >>> >>> >>> OberserListThreadSafe is also implemented through locks ( >>> https://code.google.com/p/chromium/codesearch#chromium/src/base/observer_list...), >>> so will not solve the issue wez pointed out. >>> >> >> OberserListThreadSafe holds a lock only to post a task. It always >> releases the lock before calling observers. >> >> > > Ah, I see. I'll fix that then. :) Thanks! > >> >>> I don't see a way to get rid of the lock; but I can remove the >>> ref-counting of UserInputMonitor by posting the callback to the thread that >>> creates/destroys UserInputMonior, i.e. the browser UI thread, to make >>> WeakPtr valid to use. >>> >>> How about that? >>> >>>> >>>> >>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>> base/user_input_monitor_linux.**cc<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_linux.cc> >>>> File media/base/user_input_monitor_**linux.cc (right): >>>> >>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>> base/user_input_monitor_linux.**cc#newcode138<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_linux.cc#newcode138> >>>> media/base/user_input_monitor_**linux.cc:138: if >>>> (!io_task_runner_->**BelongsToCurrentThread()) { >>>> There is potential race between StartKeyboardMonitoring() and >>>> StopKeyboardMonitoring(). If StopKeyboardMonitoring() is called on a >>>> thread other than the IO thread and then StartKeyboardMonitoring() is >>>> called the IO immediately after that then monitoring will be started and >>>> then stopped on the IO thread, while it should be stopped first and then >>>> started. I think you can avoid it by always posting a task to call >>>> StopMonitor(). >>>> >>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>> base/user_input_monitor_win.cc<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc> >>>> File media/base/user_input_monitor_**win.cc (right): >>>> >>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>> base/user_input_monitor_win.**cc#newcode114<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc#newcode114> >>>> media/base/user_input_monitor_**win.cc:114: if >>>> (!ui_task_runner_->**BelongsToCurrentThread()) { >>>> There is a same race as in Linux version of this code. Just post a task >>>> for StopMonitor()? >>>> >>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>> base/user_input_monitor_win.**cc#newcode207<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc#newcode207> >>>> media/base/user_input_monitor_**win.cc:207: ? ui::ET_KEY_RELEASED >>>> nit: operators should not be wrapped. ? goes on the previous line. >>>> >>>> https://codereview.chromium.**org/23702008/diff/20001/media/**media.gyp<https... >>>> File media/media.gyp (right): >>>> >>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>> media.gyp#newcode884<https://codereview.chromium.org/23702008/diff/20001/media/media.gyp#newcode884> >>>> media/media.gyp:884: 'sources!': [ >>>> indentation >>>> >>>> https://codereview.chromium.**org/23702008/<https://codereview.chromium.org/2... >>>> >>> >>> >> > To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
That's essentially what I and Wez were suggesting, but please consider adding Core inside of UserInputMonitor instead of a wrapper outside of it. I.e. in you code below rename the core UserInputMonitor=>UserInputMonitor::Core and the wrapper UserInputMonitorWrapper=>UserInputMonitor. Then instead of exposing core from the outer class add separate methods that call the core. On Wed, Sep 4, 2013 at 2:23 PM, Jiayang Liu <jiayl@chromium.org> wrote: > I'm planning to make this change to remove the assumption that > UserInputMonitor has to outlive the UI/IO browser threads. Please let me > know what you think. > > I'll have a UserInputMonitorWrapper class to handle the creation and > destruction of UserInputMonitor: > class UserInputMonitorWrapper { > public: > UserInputMonitorWrapper(io_task_runner, ui_task_runner); > ~UserInputMonitorWrapper(); > UserInputMonitor* user_input_monitor() { return monitor_; } > private: > UserInputMonitor* monitor_; > } > > The implementation of UserInputMonitorWrapper will be platform specifc, > for example on Linux: > UserInputMonitorWrapper::UserInputMonitorWrapper (...) { > monitor_ = new UserInputMonitorLinux(io_task_runner); > } > // Dispatch to the IO thread to delete |monitor_|. > UserInputMonitorWrapper::~UserInputMonitorWrapper() { > monitor_->io_task_runner()->PostTask( > &UserInputMonitorLinux::Shutdown, base::Owned(monitor_)); > monitor_ = NULL; > } > > Then UserInputMonitorLinux can use WeakPtr for posting tasks to the IO > thread since it will be destructed on the IO thread. > > It doesn't matter if the io_task_runner is not running when the wrapper is > destructed since base::Owned will make sure |monitor_| is not leaked. > I think you don't really need base::Owned() - just call TaskRunner::DeleteSoon() when you are ready to delete it. > > UserInputMonitorLinux::Shutdown does not need to anything except checking > monitoring has been stopped. > > > > > On Wed, Sep 4, 2013 at 11:56 AM, Jiayang Liu <jiayl@chromium.org> wrote: > >> >> >> >> On Wed, Sep 4, 2013 at 11:53 AM, Sergey Ulanov <sergeyu@chromium.org>wrote: >> >>> >>> On Wed, Sep 4, 2013 at 11:49 AM, Jiayang Liu <jiayl@chromium.org> wrote: >>> >>>> >>>> On Wed, Sep 4, 2013 at 11:40 AM, <sergeyu@chromium.org> wrote: >>>> >>>>> Looks like there are some races - see my comments. >>>>> >>>>> I already suggested in previous CLs to use ObserverListThreadSafe - it >>>>> will help >>>>> to avoid the problems Wez pointed at and also guarantees that >>>>> notifications are >>>>> delivered on the same thread on which listener is registered. You can >>>>> use it >>>>> with a locked listeners counter to detect when to start/stop >>>>> monitoring. >>>>> >>>>> I also don't like that you are making UserInputMonitor ref-counted. >>>>> You can >>>>> avoid it easily by using a "Core" object. It can be ref-counted, e.g. >>>>> as in >>>>> remoting::**LocalInputMonitorLinux, but if you destroy on the thread >>>>> on which >>>>> events are received then it won't need to be ref-counted. >>>>> >>>> >>>> >>>> OberserListThreadSafe is also implemented through locks ( >>>> https://code.google.com/p/chromium/codesearch#chromium/src/base/observer_list...), >>>> so will not solve the issue wez pointed out. >>>> >>> >>> OberserListThreadSafe holds a lock only to post a task. It always >>> releases the lock before calling observers. >>> >>> >> >> Ah, I see. I'll fix that then. :) Thanks! >> >>> >>>> I don't see a way to get rid of the lock; but I can remove the >>>> ref-counting of UserInputMonitor by posting the callback to the thread that >>>> creates/destroys UserInputMonior, i.e. the browser UI thread, to make >>>> WeakPtr valid to use. >>>> >>>> How about that? >>>> >>>>> >>>>> >>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>> base/user_input_monitor_linux.**cc<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_linux.cc> >>>>> File media/base/user_input_monitor_**linux.cc (right): >>>>> >>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>> base/user_input_monitor_linux.**cc#newcode138<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_linux.cc#newcode138> >>>>> media/base/user_input_monitor_**linux.cc:138: if >>>>> (!io_task_runner_->**BelongsToCurrentThread()) { >>>>> There is potential race between StartKeyboardMonitoring() and >>>>> StopKeyboardMonitoring(). If StopKeyboardMonitoring() is called on a >>>>> thread other than the IO thread and then StartKeyboardMonitoring() is >>>>> called the IO immediately after that then monitoring will be started >>>>> and >>>>> then stopped on the IO thread, while it should be stopped first and >>>>> then >>>>> started. I think you can avoid it by always posting a task to call >>>>> StopMonitor(). >>>>> >>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>> base/user_input_monitor_win.cc<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc> >>>>> File media/base/user_input_monitor_**win.cc (right): >>>>> >>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>> base/user_input_monitor_win.**cc#newcode114<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc#newcode114> >>>>> media/base/user_input_monitor_**win.cc:114: if >>>>> (!ui_task_runner_->**BelongsToCurrentThread()) { >>>>> There is a same race as in Linux version of this code. Just post a task >>>>> for StopMonitor()? >>>>> >>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>> base/user_input_monitor_win.**cc#newcode207<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc#newcode207> >>>>> media/base/user_input_monitor_**win.cc:207: ? ui::ET_KEY_RELEASED >>>>> nit: operators should not be wrapped. ? goes on the previous line. >>>>> >>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>> media.gyp<https://codereview.chromium.org/23702008/diff/20001/media/media.gyp> >>>>> File media/media.gyp (right): >>>>> >>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>> media.gyp#newcode884<https://codereview.chromium.org/23702008/diff/20001/media/media.gyp#newcode884> >>>>> media/media.gyp:884: 'sources!': [ >>>>> indentation >>>>> >>>>> https://codereview.chromium.**org/23702008/<https://codereview.chromium.org/2... >>>>> >>>> >>>> >>> >> > To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
On Wed, Sep 4, 2013 at 3:42 PM, Sergey Ulanov <sergeyu@chromium.org> wrote: > That's essentially what I and Wez were suggesting, but please consider > adding Core inside of UserInputMonitor instead of a wrapper outside of > it. I.e. in you code below rename the core > UserInputMonitor=>UserInputMonitor::Core and the > wrapper UserInputMonitorWrapper=>UserInputMonitor. Then instead of exposing > core from the outer class add separate methods that call the core. > > > That means the mouse listeners need to be moved into Core so that Core does not need to call back to the outer class. Does that sound good to you? > On Wed, Sep 4, 2013 at 2:23 PM, Jiayang Liu <jiayl@chromium.org> wrote: > >> I'm planning to make this change to remove the assumption that >> UserInputMonitor has to outlive the UI/IO browser threads. Please let me >> know what you think. >> >> I'll have a UserInputMonitorWrapper class to handle the creation and >> destruction of UserInputMonitor: >> class UserInputMonitorWrapper { >> public: >> UserInputMonitorWrapper(io_task_runner, ui_task_runner); >> ~UserInputMonitorWrapper(); >> UserInputMonitor* user_input_monitor() { return monitor_; } >> private: >> UserInputMonitor* monitor_; >> } >> >> The implementation of UserInputMonitorWrapper will be platform specifc, >> for example on Linux: >> UserInputMonitorWrapper::UserInputMonitorWrapper (...) { >> monitor_ = new UserInputMonitorLinux(io_task_runner); >> } >> // Dispatch to the IO thread to delete |monitor_|. >> UserInputMonitorWrapper::~UserInputMonitorWrapper() { >> monitor_->io_task_runner()->PostTask( >> &UserInputMonitorLinux::Shutdown, base::Owned(monitor_)); >> monitor_ = NULL; >> } >> >> Then UserInputMonitorLinux can use WeakPtr for posting tasks to the IO >> thread since it will be destructed on the IO thread. >> >> It doesn't matter if the io_task_runner is not running when the wrapper >> is destructed since base::Owned will make sure |monitor_| is not leaked. >> > > I think you don't really need base::Owned() - just call > TaskRunner::DeleteSoon() when you are ready to delete it. > > >> >> UserInputMonitorLinux::Shutdown does not need to anything except checking >> monitoring has been stopped. >> >> >> >> >> On Wed, Sep 4, 2013 at 11:56 AM, Jiayang Liu <jiayl@chromium.org> wrote: >> >>> >>> >>> >>> On Wed, Sep 4, 2013 at 11:53 AM, Sergey Ulanov <sergeyu@chromium.org>wrote: >>> >>>> >>>> On Wed, Sep 4, 2013 at 11:49 AM, Jiayang Liu <jiayl@chromium.org>wrote: >>>> >>>>> >>>>> On Wed, Sep 4, 2013 at 11:40 AM, <sergeyu@chromium.org> wrote: >>>>> >>>>>> Looks like there are some races - see my comments. >>>>>> >>>>>> I already suggested in previous CLs to use ObserverListThreadSafe - >>>>>> it will help >>>>>> to avoid the problems Wez pointed at and also guarantees that >>>>>> notifications are >>>>>> delivered on the same thread on which listener is registered. You can >>>>>> use it >>>>>> with a locked listeners counter to detect when to start/stop >>>>>> monitoring. >>>>>> >>>>>> I also don't like that you are making UserInputMonitor ref-counted. >>>>>> You can >>>>>> avoid it easily by using a "Core" object. It can be ref-counted, e.g. >>>>>> as in >>>>>> remoting::**LocalInputMonitorLinux, but if you destroy on the thread >>>>>> on which >>>>>> events are received then it won't need to be ref-counted. >>>>>> >>>>> >>>>> >>>>> OberserListThreadSafe is also implemented through locks ( >>>>> https://code.google.com/p/chromium/codesearch#chromium/src/base/observer_list...), >>>>> so will not solve the issue wez pointed out. >>>>> >>>> >>>> OberserListThreadSafe holds a lock only to post a task. It always >>>> releases the lock before calling observers. >>>> >>>> >>> >>> Ah, I see. I'll fix that then. :) Thanks! >>> >>>> >>>>> I don't see a way to get rid of the lock; but I can remove the >>>>> ref-counting of UserInputMonitor by posting the callback to the thread that >>>>> creates/destroys UserInputMonior, i.e. the browser UI thread, to make >>>>> WeakPtr valid to use. >>>>> >>>>> How about that? >>>>> >>>>>> >>>>>> >>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>>> base/user_input_monitor_linux.**cc<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_linux.cc> >>>>>> File media/base/user_input_monitor_**linux.cc (right): >>>>>> >>>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>>> base/user_input_monitor_linux.**cc#newcode138<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_linux.cc#newcode138> >>>>>> media/base/user_input_monitor_**linux.cc:138: if >>>>>> (!io_task_runner_->**BelongsToCurrentThread()) { >>>>>> There is potential race between StartKeyboardMonitoring() and >>>>>> StopKeyboardMonitoring(). If StopKeyboardMonitoring() is called on a >>>>>> thread other than the IO thread and then StartKeyboardMonitoring() is >>>>>> called the IO immediately after that then monitoring will be started >>>>>> and >>>>>> then stopped on the IO thread, while it should be stopped first and >>>>>> then >>>>>> started. I think you can avoid it by always posting a task to call >>>>>> StopMonitor(). >>>>>> >>>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>>> base/user_input_monitor_win.cc<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc> >>>>>> File media/base/user_input_monitor_**win.cc (right): >>>>>> >>>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>>> base/user_input_monitor_win.**cc#newcode114<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc#newcode114> >>>>>> media/base/user_input_monitor_**win.cc:114: if >>>>>> (!ui_task_runner_->**BelongsToCurrentThread()) { >>>>>> There is a same race as in Linux version of this code. Just post a >>>>>> task >>>>>> for StopMonitor()? >>>>>> >>>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>>> base/user_input_monitor_win.**cc#newcode207<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc#newcode207> >>>>>> media/base/user_input_monitor_**win.cc:207: ? ui::ET_KEY_RELEASED >>>>>> nit: operators should not be wrapped. ? goes on the previous line. >>>>>> >>>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>>> media.gyp<https://codereview.chromium.org/23702008/diff/20001/media/media.gyp> >>>>>> File media/media.gyp (right): >>>>>> >>>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>>> media.gyp#newcode884<https://codereview.chromium.org/23702008/diff/20001/media/media.gyp#newcode884> >>>>>> media/media.gyp:884: 'sources!': [ >>>>>> indentation >>>>>> >>>>>> https://codereview.chromium.**org/23702008/<https://codereview.chromium.org/2... >>>>>> >>>>> >>>>> >>>> >>> >> > To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
On Wed, Sep 4, 2013 at 3:49 PM, Jiayang Liu <jiayl@chromium.org> wrote: > > On Wed, Sep 4, 2013 at 3:42 PM, Sergey Ulanov <sergeyu@chromium.org>wrote: > >> That's essentially what I and Wez were suggesting, but please consider >> adding Core inside of UserInputMonitor instead of a wrapper outside of >> it. I.e. in you code below rename the core >> UserInputMonitor=>UserInputMonitor::Core and the >> wrapper UserInputMonitorWrapper=>UserInputMonitor. Then instead of exposing >> core from the outer class add separate methods that call the core. >> >> >> That means the mouse listeners need to be moved into Core so that Core > does not need to call back to the outer class. Does that sound good to you? > Yes. The wrapper will just delegate AddListener() and RemoveListener() calls to the core and the core will take care of storing the listeners and invoking them when necessary. > > >> On Wed, Sep 4, 2013 at 2:23 PM, Jiayang Liu <jiayl@chromium.org> wrote: >> >>> I'm planning to make this change to remove the assumption that >>> UserInputMonitor has to outlive the UI/IO browser threads. Please let me >>> know what you think. >>> >>> I'll have a UserInputMonitorWrapper class to handle the creation and >>> destruction of UserInputMonitor: >>> class UserInputMonitorWrapper { >>> public: >>> UserInputMonitorWrapper(io_task_runner, ui_task_runner); >>> ~UserInputMonitorWrapper(); >>> UserInputMonitor* user_input_monitor() { return monitor_; } >>> private: >>> UserInputMonitor* monitor_; >>> } >>> >>> The implementation of UserInputMonitorWrapper will be platform specifc, >>> for example on Linux: >>> UserInputMonitorWrapper::UserInputMonitorWrapper (...) { >>> monitor_ = new UserInputMonitorLinux(io_task_runner); >>> } >>> // Dispatch to the IO thread to delete |monitor_|. >>> UserInputMonitorWrapper::~UserInputMonitorWrapper() { >>> monitor_->io_task_runner()->PostTask( >>> &UserInputMonitorLinux::Shutdown, base::Owned(monitor_)); >>> monitor_ = NULL; >>> } >>> >>> Then UserInputMonitorLinux can use WeakPtr for posting tasks to the IO >>> thread since it will be destructed on the IO thread. >>> >>> It doesn't matter if the io_task_runner is not running when the wrapper >>> is destructed since base::Owned will make sure |monitor_| is not leaked. >>> >> >> I think you don't really need base::Owned() - just call >> TaskRunner::DeleteSoon() when you are ready to delete it. >> >> >>> >>> UserInputMonitorLinux::Shutdown does not need to anything except >>> checking monitoring has been stopped. >>> >>> >>> >>> >>> On Wed, Sep 4, 2013 at 11:56 AM, Jiayang Liu <jiayl@chromium.org> wrote: >>> >>>> >>>> >>>> >>>> On Wed, Sep 4, 2013 at 11:53 AM, Sergey Ulanov <sergeyu@chromium.org>wrote: >>>> >>>>> >>>>> On Wed, Sep 4, 2013 at 11:49 AM, Jiayang Liu <jiayl@chromium.org>wrote: >>>>> >>>>>> >>>>>> On Wed, Sep 4, 2013 at 11:40 AM, <sergeyu@chromium.org> wrote: >>>>>> >>>>>>> Looks like there are some races - see my comments. >>>>>>> >>>>>>> I already suggested in previous CLs to use ObserverListThreadSafe - >>>>>>> it will help >>>>>>> to avoid the problems Wez pointed at and also guarantees that >>>>>>> notifications are >>>>>>> delivered on the same thread on which listener is registered. You >>>>>>> can use it >>>>>>> with a locked listeners counter to detect when to start/stop >>>>>>> monitoring. >>>>>>> >>>>>>> I also don't like that you are making UserInputMonitor ref-counted. >>>>>>> You can >>>>>>> avoid it easily by using a "Core" object. It can be ref-counted, >>>>>>> e.g. as in >>>>>>> remoting::**LocalInputMonitorLinux, but if you destroy on the >>>>>>> thread on which >>>>>>> events are received then it won't need to be ref-counted. >>>>>>> >>>>>> >>>>>> >>>>>> OberserListThreadSafe is also implemented through locks ( >>>>>> https://code.google.com/p/chromium/codesearch#chromium/src/base/observer_list...), >>>>>> so will not solve the issue wez pointed out. >>>>>> >>>>> >>>>> OberserListThreadSafe holds a lock only to post a task. It always >>>>> releases the lock before calling observers. >>>>> >>>>> >>>> >>>> Ah, I see. I'll fix that then. :) Thanks! >>>> >>>>> >>>>>> I don't see a way to get rid of the lock; but I can remove the >>>>>> ref-counting of UserInputMonitor by posting the callback to the thread that >>>>>> creates/destroys UserInputMonior, i.e. the browser UI thread, to make >>>>>> WeakPtr valid to use. >>>>>> >>>>>> How about that? >>>>>> >>>>>>> >>>>>>> >>>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>>>> base/user_input_monitor_linux.**cc<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_linux.cc> >>>>>>> File media/base/user_input_monitor_**linux.cc (right): >>>>>>> >>>>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>>>> base/user_input_monitor_linux.**cc#newcode138<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_linux.cc#newcode138> >>>>>>> media/base/user_input_monitor_**linux.cc:138: if >>>>>>> (!io_task_runner_->**BelongsToCurrentThread()) { >>>>>>> There is potential race between StartKeyboardMonitoring() and >>>>>>> StopKeyboardMonitoring(). If StopKeyboardMonitoring() is called on a >>>>>>> thread other than the IO thread and then StartKeyboardMonitoring() is >>>>>>> called the IO immediately after that then monitoring will be started >>>>>>> and >>>>>>> then stopped on the IO thread, while it should be stopped first and >>>>>>> then >>>>>>> started. I think you can avoid it by always posting a task to call >>>>>>> StopMonitor(). >>>>>>> >>>>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>>>> base/user_input_monitor_win.cc<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc> >>>>>>> File media/base/user_input_monitor_**win.cc (right): >>>>>>> >>>>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>>>> base/user_input_monitor_win.**cc#newcode114<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc#newcode114> >>>>>>> media/base/user_input_monitor_**win.cc:114: if >>>>>>> (!ui_task_runner_->**BelongsToCurrentThread()) { >>>>>>> There is a same race as in Linux version of this code. Just post a >>>>>>> task >>>>>>> for StopMonitor()? >>>>>>> >>>>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>>>> base/user_input_monitor_win.**cc#newcode207<https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_monitor_win.cc#newcode207> >>>>>>> media/base/user_input_monitor_**win.cc:207: ? ui::ET_KEY_RELEASED >>>>>>> nit: operators should not be wrapped. ? goes on the previous line. >>>>>>> >>>>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>>>> media.gyp<https://codereview.chromium.org/23702008/diff/20001/media/media.gyp> >>>>>>> File media/media.gyp (right): >>>>>>> >>>>>>> https://codereview.chromium.**org/23702008/diff/20001/media/** >>>>>>> media.gyp#newcode884<https://codereview.chromium.org/23702008/diff/20001/media/media.gyp#newcode884> >>>>>>> media/media.gyp:884: 'sources!': [ >>>>>>> indentation >>>>>>> >>>>>>> https://codereview.chromium.**org/23702008/<https://codereview.chromium.org/2... >>>>>>> >>>>>> >>>>>> >>>>> >>>> >>> >> > To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
The mouse listener list is moved to the platform specific implementation, which is now separated from UserInputMonitor and always deleted on the monitoring thread (IO on Linux and UI on others). PTAL. Thanks! https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_mon... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_mon... media/base/user_input_monitor_linux.cc:138: if (!io_task_runner_->BelongsToCurrentThread()) { On 2013/09/04 18:40:09, Sergey Ulanov wrote: > There is potential race between StartKeyboardMonitoring() and > StopKeyboardMonitoring(). If StopKeyboardMonitoring() is called on a thread > other than the IO thread and then StartKeyboardMonitoring() is called the IO > immediately after that then monitoring will be started and then stopped on the > IO thread, while it should be stopped first and then started. I think you can > avoid it by always posting a task to call StopMonitor(). If the same caller calls Start and Stop on different threads, there is no way to know what's the intended ordering and I think it's expected to get undefined behavior. https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_mon... File media/base/user_input_monitor_win.cc (right): https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_mon... media/base/user_input_monitor_win.cc:207: ? ui::ET_KEY_RELEASED On 2013/09/04 18:40:09, Sergey Ulanov wrote: > nit: operators should not be wrapped. ? goes on the previous line. I don't find the rule on the style guide. But this is auto formatted by git-cl format. https://codereview.chromium.org/23702008/diff/20001/media/media.gyp File media/media.gyp (right): https://codereview.chromium.org/23702008/diff/20001/media/media.gyp#newcode884 media/media.gyp:884: 'sources!': [ On 2013/09/04 18:40:09, Sergey Ulanov wrote: > indentation Done.
Seems you're missing the most recent patch set?
Oops. Uploaded now. Thanks! On Wed, Sep 4, 2013 at 5:36 PM, <dalecurtis@chromium.org> wrote: > Seems you're missing the most recent patch set? > > https://codereview.chromium.**org/23702008/<https://codereview.chromium.org/2... > To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
Just nits really. I defer to the remoting/ team for the WIndows specific bits. https://codereview.chromium.org/23702008/diff/34001/media/base/user_input_mon... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/34001/media/base/user_input_mon... media/base/user_input_monitor_linux.cc:359: UserInputMonitorLinux::UserInputMonitorLinux( Blank line between each method. https://codereview.chromium.org/23702008/diff/34001/media/base/user_input_mon... File media/base/user_input_monitor_unittest.cc (right): https://codereview.chromium.org/23702008/diff/34001/media/base/user_input_mon... media/base/user_input_monitor_unittest.cc:46: #ifndef DISABLE_USER_INPUT_MONITOR !defined() https://codereview.chromium.org/23702008/diff/34001/media/base/user_input_mon... media/base/user_input_monitor_unittest.cc:55: scoped_ptr<UserInputMonitor> monitor = UserInputMonitor::Create( Just stack allocate?
Whoops, lgtm
https://codereview.chromium.org/23702008/diff/34001/media/base/user_input_mon... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/34001/media/base/user_input_mon... media/base/user_input_monitor_linux.cc:359: UserInputMonitorLinux::UserInputMonitorLinux( On 2013/09/06 21:51:08, DaleCurtis wrote: > Blank line between each method. Done. https://codereview.chromium.org/23702008/diff/34001/media/base/user_input_mon... File media/base/user_input_monitor_unittest.cc (right): https://codereview.chromium.org/23702008/diff/34001/media/base/user_input_mon... media/base/user_input_monitor_unittest.cc:46: #ifndef DISABLE_USER_INPUT_MONITOR On 2013/09/06 21:51:08, DaleCurtis wrote: > !defined() Done. https://codereview.chromium.org/23702008/diff/34001/media/base/user_input_mon... media/base/user_input_monitor_unittest.cc:55: scoped_ptr<UserInputMonitor> monitor = UserInputMonitor::Create( On 2013/09/06 21:51:08, DaleCurtis wrote: > Just stack allocate? But UserInputMonitor::Create returns scoped_ptr.
Thanks for removing ref-counting! There is still a problem with races between StartMonitoring() and StopMonitoring() - it should be easy to fix. https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_mon... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_mon... media/base/user_input_monitor_linux.cc:138: if (!io_task_runner_->BelongsToCurrentThread()) { On 2013/09/05 00:29:38, jiayl wrote: > On 2013/09/04 18:40:09, Sergey Ulanov wrote: > > There is potential race between StartKeyboardMonitoring() and > > StopKeyboardMonitoring(). If StopKeyboardMonitoring() is called on a thread > > other than the IO thread and then StartKeyboardMonitoring() is called the IO > > immediately after that then monitoring will be started and then stopped on the > > IO thread, while it should be stopped first and then started. I think you can > > avoid it by always posting a task to call StopMonitor(). > > If the same caller calls Start and Stop on different threads, there is no way to > know what's the intended ordering and I think it's expected to get undefined > behavior. It might not be the same caller. One object may be calling RemoveMouseListener() which would call StopMonitoring(), while completely different object is calling AddMouseListener() which calls StartMonitoring(). What matters is that the listener gets notification after registering with AddMouseListener(), but due to this race it could happen that monitoring will be stopped when it shouldn't be. https://codereview.chromium.org/23702008/diff/45001/media/base/user_input_mon... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/45001/media/base/user_input_mon... media/base/user_input_monitor_linux.cc:174: if (!io_task_runner_->BelongsToCurrentThread()) { There is still the problem that I pointed before: If some thread calls StartMonitor() and then IO thread calls StopMonitor() immediately after that then StopMonitor() will be executed before StartMonitor() is called on the IO thread. This should be easy to fix. Just add DoStartMonitor() and always post a task from StartMonitor(). StartMonitoring() and StopMonitoring() are always called with the lock held, so there is definite order in which these methods are called. The code that starts/stops monitoring on the IO thread should be always executed in the same order, but that's not guaranteed if you don't always post a task here.
Fixed the race. PTAL. Thanks! https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_mon... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/20001/media/base/user_input_mon... media/base/user_input_monitor_linux.cc:138: if (!io_task_runner_->BelongsToCurrentThread()) { On 2013/09/07 20:19:41, Sergey Ulanov wrote: > On 2013/09/05 00:29:38, jiayl wrote: > > On 2013/09/04 18:40:09, Sergey Ulanov wrote: > > > There is potential race between StartKeyboardMonitoring() and > > > StopKeyboardMonitoring(). If StopKeyboardMonitoring() is called on a thread > > > other than the IO thread and then StartKeyboardMonitoring() is called the IO > > > immediately after that then monitoring will be started and then stopped on > the > > > IO thread, while it should be stopped first and then started. I think you > can > > > avoid it by always posting a task to call StopMonitor(). > > > > If the same caller calls Start and Stop on different threads, there is no way > to > > know what's the intended ordering and I think it's expected to get undefined > > behavior. > > It might not be the same caller. One object may be calling > RemoveMouseListener() which would call StopMonitoring(), while completely > different object is calling AddMouseListener() which calls StartMonitoring(). > What matters is that the listener gets notification after registering with > AddMouseListener(), but due to this race it could happen that monitoring will be > stopped when it shouldn't be. Done. https://codereview.chromium.org/23702008/diff/45001/media/base/user_input_mon... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/45001/media/base/user_input_mon... media/base/user_input_monitor_linux.cc:174: if (!io_task_runner_->BelongsToCurrentThread()) { On 2013/09/07 20:19:41, Sergey Ulanov wrote: > There is still the problem that I pointed before: If some thread calls > StartMonitor() and then IO thread calls StopMonitor() immediately after that > then StopMonitor() will be executed before StartMonitor() is called on the IO > thread. This should be easy to fix. Just add DoStartMonitor() and always post a > task from StartMonitor(). > > StartMonitoring() and StopMonitoring() are always called with the lock held, so > there is definite order in which these methods are called. The code that > starts/stops monitoring on the IO thread should be always executed in the same > order, but that's not guaranteed if you don't always post a task here. Done.
LGTM. Just some minor nits. https://codereview.chromium.org/23702008/diff/50001/media/base/user_input_mon... File media/base/user_input_monitor_win.cc (right): https://codereview.chromium.org/23702008/diff/50001/media/base/user_input_mon... media/base/user_input_monitor_win.cc:40: // Private interface of UserInputMonitor. nit: It's more common to say something like "UserInputMonitor overrides". UserInputMonitor is not an interface, so this comment may be confusing. https://codereview.chromium.org/23702008/diff/50001/media/base/user_input_mon... media/base/user_input_monitor_win.cc:44: class Core; nit: class declaration should be before the methods. https://codereview.chromium.org/23702008/diff/50001/media/base/user_input_mon... media/base/user_input_monitor_win.cc:244: ? ui::ET_KEY_RELEASED nit: Operators normally should not be wrapped, i.e. ? should be on the previous line. Ignore me if you used clang-format to format this code. https://codereview.chromium.org/23702008/diff/50001/media/base/user_input_mon... media/base/user_input_monitor_win.cc:298: UserInputMonitorWin::~UserInputMonitorWin() { nit: empty lines between methods please.
https://codereview.chromium.org/23702008/diff/50001/media/base/user_input_mon... File media/base/user_input_monitor_win.cc (right): https://codereview.chromium.org/23702008/diff/50001/media/base/user_input_mon... media/base/user_input_monitor_win.cc:40: // Private interface of UserInputMonitor. On 2013/09/10 18:28:39, Sergey Ulanov wrote: > nit: It's more common to say something like "UserInputMonitor overrides". > UserInputMonitor is not an interface, so this comment may be confusing. Done. https://codereview.chromium.org/23702008/diff/50001/media/base/user_input_mon... media/base/user_input_monitor_win.cc:44: class Core; On 2013/09/10 18:28:39, Sergey Ulanov wrote: > nit: class declaration should be before the methods. Done. https://codereview.chromium.org/23702008/diff/50001/media/base/user_input_mon... media/base/user_input_monitor_win.cc:298: UserInputMonitorWin::~UserInputMonitorWin() { On 2013/09/10 18:28:39, Sergey Ulanov wrote: > nit: empty lines between methods please. Done.
https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:62: class UserInputMonitorLinux::Core : public base::MessagePumpLibevent::Watcher { nit: If you rename this UserInputMonitorLinuxCore and define it before UserInputMonitorLinux, above, then you can avoid needing to forward-define it in UIML's private section. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:103: Display* display_; nit: Suggest |display_control_| and |display_record_| for these, to make it clearer why you need two. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:127: DCHECK_EQ(0u, mouse_listeners_count_); nit: You could also mouse_listeners_.AssertEmpty() here if you want. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:138: { If you move |lock_|, |mouse_listeners_count_|, |weak_factory_| into the main class, and keep a copy of |io_task_runner_| there as well then you can move the lock/increment/post logic back to the outer class. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:140: mouse_listeners_count_++; Why not keep this count on the IO thread, and increment/decrement when processing Start/StopMonitor()? Then you wouldn't need the lock. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:171: void UserInputMonitorLinux::Core::StartKeyboardMonitoring() { If you move |weak_factory_| into the outer class, and keep a copy of |io_task_runner_| there then you don't need these boilerplate methods - you can Bind() to Start/StopMonitor directly from StartKeyboardMonitoring instead. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:189: counter_.Reset(); You're resetting the counter every time StartKeyboardMonitoring() is called - doesn't that mean that if you get multiple calls then earlier callers might be confused by the event count being reset when later callers start monitoring? https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... File media/base/user_input_monitor_win.cc (right): https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:52: class UserInputMonitorWin::Core { See comment on Linux impl https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:88: size_t mouse_listeners_count_; See comments on Linux impl
PTAL. Thanks! https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:62: class UserInputMonitorLinux::Core : public base::MessagePumpLibevent::Watcher { On 2013/09/10 21:09:00, Wez wrote: > nit: If you rename this UserInputMonitorLinuxCore and define it before > UserInputMonitorLinux, above, then you can avoid needing to forward-define it in > UIML's private section. Done. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:103: Display* display_; On 2013/09/10 21:09:00, Wez wrote: > nit: Suggest |display_control_| and |display_record_| for these, to make it > clearer why you need two. Done. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:127: DCHECK_EQ(0u, mouse_listeners_count_); On 2013/09/10 21:09:00, Wez wrote: > nit: You could also mouse_listeners_.AssertEmpty() here if you want. Done. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:138: { On 2013/09/10 21:09:00, Wez wrote: > If you move |lock_|, |mouse_listeners_count_|, |weak_factory_| into the main > class, and keep a copy of |io_task_runner_| there as well then you can move the > lock/increment/post logic back to the outer class. lock is removed now; "post" cannot be done from the outer class because the listener list must be updated on the calling thread. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:140: mouse_listeners_count_++; On 2013/09/10 21:09:00, Wez wrote: > Why not keep this count on the IO thread, and increment/decrement when > processing Start/StopMonitor()? Then you wouldn't need the lock. Done. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:171: void UserInputMonitorLinux::Core::StartKeyboardMonitoring() { On 2013/09/10 21:09:00, Wez wrote: > If you move |weak_factory_| into the outer class, and keep a copy of > |io_task_runner_| there then you don't need these boilerplate methods - you can > Bind() to Start/StopMonitor directly from StartKeyboardMonitoring instead. Done. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:189: counter_.Reset(); On 2013/09/10 21:09:00, Wez wrote: > You're resetting the counter every time StartKeyboardMonitoring() is called - > doesn't that mean that if you get multiple calls then earlier callers might be > confused by the event count being reset when later callers start monitoring? The base class makes sure that StartKeyboardMonitoring is only called for the first external caller, so the count is consistent for each caller. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... File media/base/user_input_monitor_win.cc (right): https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:52: class UserInputMonitorWin::Core { On 2013/09/10 21:09:00, Wez wrote: > See comment on Linux impl Done. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_win.cc:88: size_t mouse_listeners_count_; On 2013/09/10 21:09:00, Wez wrote: > See comments on Linux impl Done.
https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:138: { On 2013/09/10 23:14:19, jiayl wrote: > On 2013/09/10 21:09:00, Wez wrote: > > If you move |lock_|, |mouse_listeners_count_|, |weak_factory_| into the main > > class, and keep a copy of |io_task_runner_| there as well then you can move > the > > lock/increment/post logic back to the outer class. > lock is removed now; "post" cannot be done from the outer class because the > listener list must be updated on the calling thread. Sorry, I don't understand that logic. Calling PostTask() in UserInputMonitor::AddMouseListener() immediately after core_->AddMouseListener() is equivalent to calling it here, surely? https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:189: counter_.Reset(); On 2013/09/10 23:14:19, jiayl wrote: > On 2013/09/10 21:09:00, Wez wrote: > > You're resetting the counter every time StartKeyboardMonitoring() is called - > > doesn't that mean that if you get multiple calls then earlier callers might be > > confused by the event count being reset when later callers start monitoring? > The base class makes sure that StartKeyboardMonitoring is only called for the > first external caller, so the count is consistent for each caller. Why not do the same for the mouse? i.e: AddMouseListener(listener) // adds the Observer Lock mouse_listener_count_++ if (mouse_listener_count == 1) StartMonitor(MOUSE_TYPE); Unlock So long as the counter increment/decrement & Start/Stop occur with the locked held this won't be racey. https://codereview.chromium.org/23702008/diff/65001/media/base/user_input_mon... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/65001/media/base/user_input_mon... media/base/user_input_monitor_linux.cc:58: return weak_factory_.GetWeakPtr(); You can avoid this ugly WeakPtr getter by keeping the |weak_factory_| in UserInputMonitor and posting the OnMouseListenerAdded/Removed() tasks from its Add/RemoveMouseListener() methods. You just have to remember to |weak_factory_.Invalidate()| in ~UserInputMonitor() before you call DeleteSoon() on the core.
https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:138: { On 2013/09/11 08:03:42, Wez wrote: > On 2013/09/10 23:14:19, jiayl wrote: > > On 2013/09/10 21:09:00, Wez wrote: > > > If you move |lock_|, |mouse_listeners_count_|, |weak_factory_| into the main > > > class, and keep a copy of |io_task_runner_| there as well then you can move > > the > > > lock/increment/post logic back to the outer class. > > lock is removed now; "post" cannot be done from the outer class because the > > listener list must be updated on the calling thread. > > Sorry, I don't understand that logic. Calling PostTask() in > UserInputMonitor::AddMouseListener() immediately after core_->AddMouseListener() > is equivalent to calling it here, surely? Core::AddMouseListener updates the listener list in the calling thread, not in the posted task. If we don't update the listener list in the calling thread, we may call into destroyed listener since the caller may destroy the listener immediately after calling RemoveListener. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:189: counter_.Reset(); On 2013/09/11 08:03:42, Wez wrote: > On 2013/09/10 23:14:19, jiayl wrote: > > On 2013/09/10 21:09:00, Wez wrote: > > > You're resetting the counter every time StartKeyboardMonitoring() is called > - > > > doesn't that mean that if you get multiple calls then earlier callers might > be > > > confused by the event count being reset when later callers start monitoring? > > The base class makes sure that StartKeyboardMonitoring is only called for the > > first external caller, so the count is consistent for each caller. > > Why not do the same for the mouse? i.e: > > AddMouseListener(listener) // adds the Observer > Lock > mouse_listener_count_++ > if (mouse_listener_count == 1) > StartMonitor(MOUSE_TYPE); > Unlock > > So long as the counter increment/decrement & Start/Stop occur with the locked > held this won't be racey. What's the benefit? I see two shortcomings instead: 1. the listener count and the listener list will be scattered in two classes thus harder to maintain; 2. it reintroduces the lock that was removed in this patch. https://codereview.chromium.org/23702008/diff/65001/media/base/user_input_mon... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/65001/media/base/user_input_mon... media/base/user_input_monitor_linux.cc:58: return weak_factory_.GetWeakPtr(); On 2013/09/11 08:03:42, Wez wrote: > You can avoid this ugly WeakPtr getter by keeping the |weak_factory_| in > UserInputMonitor and posting the OnMouseListenerAdded/Removed() tasks from its > Add/RemoveMouseListener() methods. > > You just have to remember to |weak_factory_.Invalidate()| in ~UserInputMonitor() > before you call DeleteSoon() on the core. To reiterate why PostTask to IO thread from UserInputMonitor will not work: 1. the listener list has to live in Core so that Core does not need to callback to UserInputMonitor. Calling back to UserInputMonitor is problematic because WeakPtr does not work across threads (i.e. UserInputMonitor will be deref'd on IO thread but invalidated on UI thread) and we don't want to add ref counting for UserInputMonitor. 2. Because of #1, Core is responsible to update the listener list. It has to happen on the calling thread, since the caller may destroy the listener immediately after calling RemoveListener. So we cannot PostTask to IO thread from UserInputMonitor.
Wez, I think it's better if we don't call X Window or Windows APIs with any lock. In the latest patch set they are always called without lock, but on the same thread. If we call X Window with the lock held then we will also need to hold it when processing events, which would make it doing it correctly harder.
What I suggested was e.g. for AddMouseListener(MouseListener): 1. Add MouseListener to thread-safe ObserverList. 2. Take lock. 3. If mouse listener count is zero then call platform-specific StartMonitor(MOUSE_EVENT), which re-posts StartMonitor(MOUSE_EVENT) to the monitor thread. 4. Increment mouse listener count. 5. Release lock. And similarly for Remove*Listener(). OS calls will be processed on the monitor thread, w/out the lock held. On 11 September 2013 21:25, <sergeyu@chromium.org> wrote: > Wez, I think it's better if we don't call X Window or Windows APIs with any > lock. In the latest patch set they are always called without lock, but on > the > same thread. > > If we call X Window with the lock held then we will also need to hold it > when > processing events, which would make it doing it correctly harder. > > https://codereview.chromium.**org/23702008/<https://codereview.chromium.org/2... > To unsubscribe from this group and stop receiving emails from it, send an email to chromium-reviews+unsubscribe@chromium.org.
Moved the common logic of adding/removing mouse listeners into the base class to avoid duplication. The observer list is now created by the base class and shared with Core so that callbacks do not through the base class. PTAL. Thanks!
LGTM but please see SupportsWeakPtr comments. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:138: { On 2013/09/10 23:14:19, jiayl wrote: > On 2013/09/10 21:09:00, Wez wrote: > > If you move |lock_|, |mouse_listeners_count_|, |weak_factory_| into the main > > class, and keep a copy of |io_task_runner_| there as well then you can move > the > > lock/increment/post logic back to the outer class. > lock is removed now; "post" cannot be done from the outer class because the > listener list must be updated on the calling thread. True, you would need to add the observer from the outer class as well , before posting StartMonitor() to the Core. https://codereview.chromium.org/23702008/diff/3001/media/base/user_input_moni... media/base/user_input_monitor_linux.cc:138: { On 2013/09/11 16:57:10, jiayl wrote: > On 2013/09/11 08:03:42, Wez wrote: > > On 2013/09/10 23:14:19, jiayl wrote: > > > On 2013/09/10 21:09:00, Wez wrote: > > > > If you move |lock_|, |mouse_listeners_count_|, |weak_factory_| into the > main > > > > class, and keep a copy of |io_task_runner_| there as well then you can > move > > > the > > > > lock/increment/post logic back to the outer class. > > > lock is removed now; "post" cannot be done from the outer class because the > > > listener list must be updated on the calling thread. > > > > Sorry, I don't understand that logic. Calling PostTask() in > > UserInputMonitor::AddMouseListener() immediately after > core_->AddMouseListener() > > is equivalent to calling it here, surely? > Core::AddMouseListener updates the listener list in the calling thread, not in > the posted task. If we don't update the listener list in the calling thread, we > may call into destroyed listener since the caller may destroy the listener > immediately after calling RemoveListener. Yes, see above re updating the listener list from the outer class. https://codereview.chromium.org/23702008/diff/65001/media/base/user_input_mon... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/65001/media/base/user_input_mon... media/base/user_input_monitor_linux.cc:58: return weak_factory_.GetWeakPtr(); On 2013/09/11 16:57:10, jiayl wrote: > On 2013/09/11 08:03:42, Wez wrote: > > You can avoid this ugly WeakPtr getter by keeping the |weak_factory_| in > > UserInputMonitor and posting the OnMouseListenerAdded/Removed() tasks from its > > Add/RemoveMouseListener() methods. > > > > You just have to remember to |weak_factory_.Invalidate()| in > ~UserInputMonitor() > > before you call DeleteSoon() on the core. > To reiterate why PostTask to IO thread from UserInputMonitor will not work: > 1. the listener list has to live in Core so that Core does not need to callback > to UserInputMonitor. Calling back to UserInputMonitor is problematic because > WeakPtr does not work across threads (i.e. UserInputMonitor will be deref'd on > IO thread but invalidated on UI thread) and we don't want to add ref counting > for UserInputMonitor. > 2. Because of #1, Core is responsible to update the listener list. It has to > happen on the calling thread, since the caller may destroy the listener > immediately after calling RemoveListener. So we cannot PostTask to IO thread > from UserInputMonitor. You could add the listener from UserInputMonitor, though, before posting the task. It'd mean providing a scoped_refptr<> mouse_listeners() getter for UserInputMonitor to use, but since Core is an internal implementation detail, that seems reasonable, and it saves the boilerplate Add/RemoveMouseListener() and GetWeakPtr() calls on Core. You'd need to re-instate the Lock around the mouse counter updates for that to work, but since that's how keyboard is handled, that doesn't seem unreasonable. https://codereview.chromium.org/23702008/diff/20002/media/base/user_input_mon... File media/base/user_input_monitor.h (right): https://codereview.chromium.org/23702008/diff/20002/media/base/user_input_mon... media/base/user_input_monitor.h:81: size_t mouse_listeners_count_; nit: Name these two counters consistently, e.g. mouse_monitor_count_, keyboard_monitor_count_ https://codereview.chromium.org/23702008/diff/20002/media/base/user_input_mon... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/20002/media/base/user_input_mon... media/base/user_input_monitor_linux.cc:41: public base::SupportsWeakPtr<UserInputMonitorLinuxCore> { You have to be careful using SupportsWeakPtr - WeakPtrs it dispenses are only invalidated when the base-class dtor runs, which only happens after the derived class and its members have been destroyed. I think it's cleaner here to have UserInputMonitorLinux create a WeakPtrFactory wrapping the Core, and to explicitly Invalidate() that before posting the deletion task for the Core. https://codereview.chromium.org/23702008/diff/20002/media/base/user_input_mon... File media/base/user_input_monitor_win.cc (right): https://codereview.chromium.org/23702008/diff/20002/media/base/user_input_mon... media/base/user_input_monitor_win.cc:30: : public base::SupportsWeakPtr<UserInputMonitorWinCore> { See comment on Linux impl re SupportsWeakPtr
https://codereview.chromium.org/23702008/diff/20002/media/base/user_input_mon... File media/base/user_input_monitor_linux.cc (right): https://codereview.chromium.org/23702008/diff/20002/media/base/user_input_mon... media/base/user_input_monitor_linux.cc:41: public base::SupportsWeakPtr<UserInputMonitorLinuxCore> { On 2013/09/13 10:01:27, Wez wrote: > You have to be careful using SupportsWeakPtr - WeakPtrs it dispenses are only > invalidated when the base-class dtor runs, which only happens after the derived > class and its members have been destroyed. > > I think it's cleaner here to have UserInputMonitorLinux create a WeakPtrFactory > wrapping the Core, and to explicitly Invalidate() that before posting the > deletion task for the Core. I don't think WeakPtrFactory in UserInputMonitorLinux will work, because we need to invalidate it on the monitoring thread, thus PostTask from the dtor of UserInputMonitorLinux. But the reference to WeakPtrFactory will be immediately invalid because UserInputMonitorLinux is destroyed. SupportsWeakPtr should not a problem in this use case. The WeakPtr's are only used on the monitoring thread. It's dereferenced either before or after the Core is fully destructed on the monitoring thread, not in the middle. If DeleteSoon fails and the Core is deleted on the browser main thread, that means the monitoring thread does not exist anymore so it doesn't matter.
CQ is trying da patch. Follow status at https://chromium-status.appspot.com/cq/jiayl@chromium.org/23702008/20002
CQ is trying da patch. Follow status at https://chromium-status.appspot.com/cq/jiayl@chromium.org/23702008/82001
Retried try job too often on linux_chromeos for step(s) media_unittests http://build.chromium.org/p/tryserver.chromium/buildstatus?builder=linux_chro...
CQ is trying da patch. Follow status at https://chromium-status.appspot.com/cq/jiayl@chromium.org/23702008/103001
Message was sent while issue was closed.
Change committed as 223223
CQ is trying da patch. Follow status at https://chromium-status.appspot.com/cq/jiayl@chromium.org/23702008/12001
CQ is trying da patch. Follow status at https://chromium-status.appspot.com/cq/jiayl@chromium.org/23702008/119001
Message was sent while issue was closed.
Change committed as 223260 |