base::ThreadTaskRunnerHandle::Get() crashes

179 views
Skip to first unread message

Anton Smirnov

unread,
Aug 22, 2017, 4:11:08 AM8/22/17
to Chromium-dev
Hey, guys.

I'm working on integration of some library to be used in Chromium fork (Qualcomm fork). In order to do some work i need v8 instance to be created
in main process (to be accessed in chrome_network_delegate). I'm trying to create new IsolateHolder instance and get isolate instance from it with `isolate()`.
For this i have to pass SingleThreadTaskRunner instance to IsolateHolder ctor. I've tried to use `base::ThreadTaskRunnerHandle::Get()` but it crashes.

I've looked into ThreadTaskRunnerHandle internals and saw it uses LAZY_INSTANCE_INITIALIZER so i expect it to be created on the first invocation.
But in fact `isSet` returns `false` and Get() crashes because Pointer() is `nullptr`. Unfortunately i have no idea on what's going on.

I've found v8_test.cc but it uses `base::ThreadTaskRunnerHandle::Get()` and seems to be fine here.

Any help is highly appreciated.

PS. I've tried to pass MessageLoop instance .task_runner() but it crashes for some reason later.
PPS. I'm not advanced C++ developer (Java/Android)

David Turner

unread,
Aug 22, 2017, 5:58:33 AM8/22/17
to d...@antonsmirnov.name, Chromium-dev
On Tue, Aug 22, 2017 at 10:11 AM, Anton Smirnov <d...@antonsmirnov.name> wrote:
Hey, guys.

I'm working on integration of some library to be used in Chromium fork (Qualcomm fork). In order to do some work i need v8 instance to be created
in main process (to be accessed in chrome_network_delegate). I'm trying to create new IsolateHolder instance and get isolate instance from it with `isolate()`.
For this i have to pass SingleThreadTaskRunner instance to IsolateHolder ctor. I've tried to use `base::ThreadTaskRunnerHandle::Get()` but it crashes.

I've looked into ThreadTaskRunnerHandle internals and saw it uses LAZY_INSTANCE_INITIALIZER so i expect it to be created on the first invocation.
But in fact `isSet` returns `false` and Get() crashes because Pointer() is `nullptr`. Unfortunately i have no idea on what's going on.


Are you sure that's the reason for the crash? Because it doesn't make any sense (a base::LazyInstance<scoped_refptr<Foo>>::Pointer() cannot return null, at worst it will return the address of a scoped_refpt<Foo> instance that points to nullptr, and Get() should just return a reference to it).

I suspect you're hitting the CHECK() inside ThreadTaskRunnerHandle::Get(), which has a rather unfortunate, as in "technically correct, but unhelpful", error message, which should appear in your log.

From what I understand of the current task/thread/scheduler/message_loop/task_runner architecture:
  • Each thread in Chromium can be associated with one (and at most one) TaskRunner instance.

  • ThreadTaskRunnerHandle::Get() is a convenience function used to retrieve the TaskRunner instance for the current thread,
    but it will crash if you haven't set the thread-specific instance previously. This function is called implicitly by many other task-related
    functions (e.g. base::PostTask() ends up doing so) so it is important to set this up properly early.

  • Normally, this thread setup is done by creating a new ThreadTaskRunnerHandle() (passing the desired TaskRunner to the constructor).
    This is done automatically for you by other classes. E.g. Constructing a base::MessageLoop instance does that for you (see base::MessageLoop::BindToCurrentThread(), called by the default constructor, or by the base::Thread inner loop).
It looks like you're trying to use Chromium task-related functions in a custom program that is not Chromium itself. If so, you will need to perform specific initialization steps:

1) Create a base::MessageLoop instance in the current / main thread.

2) Call base::TaskScheduler::Create() (or base::TaskScheduler::CreateAndStartWithDefaultParams()). The base::TaskScheduler is a global per-process object that must be initialized at program startup (or when a shared library that links against its own version of //base is loaded/started). Failure to do so will result in other runtime crashes (with equally cryptic error messages).

3) You may also need to call base::CreateSingleThreadTaskRunner() or base::CreateSequencedTaskRunner() at some point, but that doesn't seem always necessary.

I must admit that I'm mostly confused by all this too, I had to discover it on my own recently, experimenting for something else entirely (loading a shared library with its own copy of //base linked in).

I believe that most of this is still in flux (there is a huge effort to move from thread-based task processing to sequence-based one). This implies a lot of refactoring, and it is sometimes hard to understand what is part of the final design, and what is transitive and/or deprecated. Hopefully some real expert might be able to complement or correct what I just wrote.
 
I've found v8_test.cc but it uses `base::ThreadTaskRunnerHandle::Get()` and seems to be fine here.


That's because the corresponding test class instanciates a base::test::ScopedTaskEnvironment, which does all the initialization for you during unit-testing (have a look at its constructor code).
 
Any help is highly appreciated.

PS. I've tried to pass MessageLoop instance .task_runner() but it crashes for some reason later.
PPS. I'm not advanced C++ developer (Java/Android)

--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev+unsubscribe@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/93c2a055-9e0f-46bc-b1fd-53673483ae80%40chromium.org.

Anton Smirnov

unread,
Aug 22, 2017, 6:32:49 AM8/22/17
to Chromium-dev, d...@antonsmirnov.name, di...@chromium.org
Hi, Dave.

Thanks for the reply.


On Tuesday, August 22, 2017 at 2:58:33 PM UTC+5, David Turner wrote:

On Tue, Aug 22, 2017 at 10:11 AM, Anton Smirnov <d...@antonsmirnov.name> wrote:
Hey, guys.

I'm working on integration of some library to be used in Chromium fork (Qualcomm fork). In order to do some work i need v8 instance to be created
in main process (to be accessed in chrome_network_delegate). I'm trying to create new IsolateHolder instance and get isolate instance from it with `isolate()`.
For this i have to pass SingleThreadTaskRunner instance to IsolateHolder ctor. I've tried to use `base::ThreadTaskRunnerHandle::Get()` but it crashes.

I've looked into ThreadTaskRunnerHandle internals and saw it uses LAZY_INSTANCE_INITIALIZER so i expect it to be created on the first invocation.
But in fact `isSet` returns `false` and Get() crashes because Pointer() is `nullptr`. Unfortunately i have no idea on what's going on.


Are you sure that's the reason for the crash? Because it doesn't make any sense (a base::LazyInstance<scoped_refptr<Foo>>::Pointer() cannot return null, at worst it will return the address of a scoped_refpt<Foo> instance that points to nullptr, and Get() should just return a reference to it).

Oh, yes, you're right - it's not Pointer(), but Get() to return 'nullptr'. BTW the original method code in my sources is a bit different to the actual Chromium and i've added debug output:

// static
scoped_refptr<SingleThreadTaskRunner> ThreadTaskRunnerHandle::Get() {
  base::ThreadLocalPointer<base::ThreadTaskRunnerHandle>* ptr = lazy_tls_ptr.Pointer();
  LOG(WARNING) << "Me: ttrh = " << ptr;
  ThreadTaskRunnerHandle* current = ptr->Get();
  LOG(WARNING) << "Me: ttrh.Get() = " << current;
  DCHECK(current);
  return current->task_runner_;
}

and it outputs:
08-22 15:22:35.353 7511-7511 W/chromium: [WARNING:thread_task_runner_handle.cc(28)] Me: ttrh = 0x9f1359b8
08-22 15:22:35.353 7511-7511 W/chromium: [WARNING:thread_task_runner_handle.cc(30)] Me: ttrh.Get() = 0

 

I suspect you're hitting the CHECK() inside ThreadTaskRunnerHandle::Get(), which has a rather unfortunate, as in "technically correct, but unhelpful", error message, which should appear in your log.


You're right, but i did not have log output message because in my sources the check message is missing.
 
From what I understand of the current task/thread/scheduler/message_loop/task_runner architecture:
  • Each thread in Chromium can be associated with one (and at most one) TaskRunner instance.

  • ThreadTaskRunnerHandle::Get() is a convenience function used to retrieve the TaskRunner instance for the current thread,
    but it will crash if you haven't set the thread-specific instance previously.
It seems to be my case.
 
  • This function is called implicitly by many other task-related
    functions (e.g. base::PostTask() ends up doing so) so it is important to set this up properly early.

  • Normally, this thread setup is done by creating a new ThreadTaskRunnerHandle() (passing the desired TaskRunner to the constructor).
    This is done automatically for you by other classes. E.g. Constructing a base::MessageLoop instance does that for you (see base::MessageLoop::BindToCurrentThread(), called by the default constructor, or by the base::Thread inner loop).
That's strange as i'm having MessageLoop instance declared as global variable and i've tried to pass it's `loop_.thread_runner()` result to IsolateHolder ctor instead of 'ThreadTaskRunnerHandle::Get()'. I will double check it. Probably the reason is that it's not attached to current thread or smth.
 
It looks like you're trying to use Chromium task-related functions in a custom program that is not Chromium itself.

No, it's chromium browser on android (Qualcomm fork).
 
If so, you will need to perform specific initialization steps:

1) Create a base::MessageLoop instance in the current / main thread.

2) Call base::TaskScheduler::Create() (or base::TaskScheduler::CreateAndStartWithDefaultParams()). The base::TaskScheduler is a global per-process object that must be initialized at program startup (or when a shared library that links against its own version of //base is loaded/started). Failure to do so will result in other runtime crashes (with equally cryptic error messages).

3) You may also need to call base::CreateSingleThreadTaskRunner() or base::CreateSequencedTaskRunner() at some point, but that doesn't seem always necessary.

Thanks for pointing the way, it's really helpful.
 

I must admit that I'm mostly confused by all this too, I had to discover it on my own recently, experimenting for something else entirely (loading a shared library with its own copy of //base linked in).

I believe that most of this is still in flux (there is a huge effort to move from thread-based task processing to sequence-based one). This implies a lot of refactoring, and it is sometimes hard to understand what is part of the final design, and what is transitive and/or deprecated. Hopefully some real expert might be able to complement or correct what I just wrote.
 
I've found v8_test.cc but it uses `base::ThreadTaskRunnerHandle::Get()` and seems to be fine here.


That's because the corresponding test class instanciates a base::test::ScopedTaskEnvironment, which does all the initialization for you during unit-testing (have a look at its constructor code).

Thanks a lot, now i know what can be wrong at least. 
 
 
Any help is highly appreciated.

PS. I've tried to pass MessageLoop instance .task_runner() but it crashes for some reason later.
PPS. I'm not advanced C++ developer (Java/Android)

--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev...@chromium.org.

David Turner

unread,
Aug 22, 2017, 12:13:01 PM8/22/17
to Anton Smirnov, Chromium-dev
Hello Anton,

It looks like you have an older version of the Chromium sources, so it is hard to know exactly what's going on
(as I wrote, a lot of this code seems to be under heavy refactoring). On the other hand, I'm pretty sure that
base::ThreadTaskRunnerHandle::Get() crashing means that you're calling it from a thread that was not
properly setup.

For the record, global variables are initialized at library load-time on Android, which happens on a temporary
background thread on Android (IIRC, to allow Java initialization happening in the main thread to continue in
parallel). That may explain your issue.

Anton Smirnov

unread,
Aug 23, 2017, 8:42:23 AM8/23/17
to Chromium-dev, d...@antonsmirnov.name
Hi, David.


On Tuesday, August 22, 2017 at 9:13:01 PM UTC+5, David Turner wrote:
Hello Anton,

It looks like you have an older version of the Chromium sources, so it is hard to know exactly what's going on
(as I wrote, a lot of this code seems to be under heavy refactoring).

Yes, i'm using Qualcomm fork of Chromium (branch 58).
 
On the other hand, I'm pretty sure that
base::ThreadTaskRunnerHandle::Get() crashing means that you're calling it from a thread that was not
properly setup.

For the record, global variables are initialized at library load-time on Android, which happens on a temporary
background thread on Android (IIRC, to allow Java initialization happening in the main thread to continue in
parallel). That may explain your issue.

Yes, i've faced that i've been trying to access JNI from Java before native methods are registered.
I've found that `RegisterJNI` happens on background thread which was actually Android AsyncTask thread.

I've found TashScheduler to be `nullptr` and it made me think it's not yet initialized and that was the actual reason -
i've moved invocation to happen a bit later (Android Activity 'startwithNative' from 'onCreate') and TaskScheduler was not 'nullptr' and
everything start work as expected.

Now i'm having another issue - the UI is sluggish and the webpage is not actually rendered.
My ideas is that something (tasks) happens on current thread (and it's UI thread) and it should be moved to background thread.
Just thoughts though. As i'm creating MessageLoop with the thread and i think it can be the reason.

David Turner

unread,
Aug 23, 2017, 4:26:29 PM8/23/17
to Anton Smirnov, Chromium-dev
On Wed, Aug 23, 2017 at 2:42 PM, Anton Smirnov <d...@antonsmirnov.name> wrote:
I've found TashScheduler to be `nullptr` and it made me think it's not yet initialized and that was the actual reason -
i've moved invocation to happen a bit later (Android Activity 'startwithNative' from 'onCreate') and TaskScheduler was not 'nullptr' and
everything start work as expected.

Makes sense, glad you could make it work.
 
Now i'm having another issue - the UI is sluggish and the webpage is not actually rendered.
My ideas is that something (tasks) happens on current thread (and it's UI thread) and it should be moved to background thread.
Just thoughts though. As i'm creating MessageLoop with the thread and i think it can be the reason.

Sorry, but I can't really help you here :(
 
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev+unsubscribe@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/6225f59b-6212-4a7c-b899-e1147fa5e6b9%40chromium.org.

Charles Harrison

unread,
Aug 23, 2017, 4:30:30 PM8/23/17
to di...@google.com, Anton Smirnov, Chromium-dev
about:tracing is a wonderful tool for debugging performance problems, if you haven't tried it already.

Gabriel Charette

unread,
Aug 24, 2017, 11:57:44 AM8/24/17
to di...@google.com, d...@antonsmirnov.name, Chromium-dev


On mar. 22 août 2017 02 h 56 David Turner <di...@chromium.org> wrote:
On Tue, Aug 22, 2017 at 10:11 AM, Anton Smirnov <d...@antonsmirnov.name> wrote:
Hey, guys.

I'm working on integration of some library to be used in Chromium fork (Qualcomm fork). In order to do some work i need v8 instance to be created
in main process (to be accessed in chrome_network_delegate). I'm trying to create new IsolateHolder instance and get isolate instance from it with `isolate()`.
For this i have to pass SingleThreadTaskRunner instance to IsolateHolder ctor. I've tried to use `base::ThreadTaskRunnerHandle::Get()` but it crashes.

I've looked into ThreadTaskRunnerHandle internals and saw it uses LAZY_INSTANCE_INITIALIZER so i expect it to be created on the first invocation.
But in fact `isSet` returns `false` and Get() crashes because Pointer() is `nullptr`. Unfortunately i have no idea on what's going on.


Are you sure that's the reason for the crash? Because it doesn't make any sense (a base::LazyInstance<scoped_refptr<Foo>>::Pointer() cannot return null, at worst it will return the address of a scoped_refpt<Foo> instance that points to nullptr, and Get() should just return a reference to it).

I suspect you're hitting the CHECK() inside ThreadTaskRunnerHandle::Get(), which has a rather unfortunate, as in "technically correct, but unhelpful", error message, which should appear in your log.

From what I understand of the current task/thread/scheduler/message_loop/task_runner architecture:
  • Each thread in Chromium can be associated with one (and at most one) TaskRunner instance.

  • ThreadTaskRunnerHandle::Get() is a convenience function used to retrieve the TaskRunner instance for the current thread,
    but it will crash if you haven't set the thread-specific instance previously. This function is called implicitly by many other task-related
    functions (e.g. base::PostTask() ends up doing so) so it is important to set this up properly early.

  • Normally, this thread setup is done by creating a new ThreadTaskRunnerHandle() (passing the desired TaskRunner to the constructor).
    This is done automatically for you by other classes. E.g. Constructing a base::MessageLoop instance does that for you (see base::MessageLoop::BindToCurrentThread(), called by the default constructor, or by the base::Thread inner loop).

This is all correct David :), thanks! It should be extremely rare to have to set ThreadTaskRunnerHandle on your own now. You should indeed be using something that sets it for you. This is part of what the comment on the CHECK in ThreadTaskRunnerHandle::Get() is trying to convey (there was no message at all until very recently; I just added it to try to alleviate confusion when it is hit, which from what I'd seen happened mostly when someone migrated code to a SequencedTaskRunner which had a component requiring a ThreadTaskRunnerHandle). I'm sorry to hear it's not useful, I'm open to suggestions, I'm trying to make many checks in //base more meaningful with opinionated hints about the most likely fix rather than generic failure. As such I'm happy to take changes improving any existing check as you see fit. The current messages are biased towards helping Chromium devs doing the average thing in Chromium more than someone setting up a new threading environment from scratch though (and I think that's ok).

It looks like you're trying to use Chromium task-related functions in a custom program that is not Chromium itself. If so, you will need to perform specific initialization steps:

1) Create a base::MessageLoop instance in the current / main thread.

2) Call base::TaskScheduler::Create() (or base::TaskScheduler::CreateAndStartWithDefaultParams()). The base::TaskScheduler is a global per-process object that must be initialized at program startup (or when a shared library that links against its own version of //base is loaded/started). Failure to do so will result in other runtime crashes (with equally cryptic error messages).

I highly recommend you add dcheck_always_on = "true" to your GN args when debugging issues in //base. As I mentioned above I'm trying hard to have DCHECKs about everything that can be done wrong in the threading+tasks part of //base. If you do so the error for using post_task.h without initializing TaskScheduler shouldn't be cryptic (ref. post_task.cc).


3) You may also need to call base::CreateSingleThreadTaskRunner() or base::CreateSequencedTaskRunner() at some point, but that doesn't seem always necessary.

I must admit that I'm mostly confused by all this too, I had to discover it on my own recently, experimenting for something else entirely (loading a shared library with its own copy of //base linked in).

I believe that most of this is still in flux (there is a huge effort to move from thread-based task processing to sequence-based one). This implies a lot of refactoring, and it is sometimes hard to understand what is part of the final design, and what is transitive and/or deprecated. Hopefully some real expert might be able to complement or correct what I just wrote.

Agreed. The reason we're doing all of this is that it was already a mess before and it's hard to make the transition phase have any less parts than the original state. We're getting there though! Ultimately we'd like to have TaskScheduler be the only way to PostTask (at first on all but UI/IO threads and ultimately taking those over too as special cases). And base::test:: ScopedTaskEnvironment be the only test construct needed for unit testing (deprecating and ultimately removing the many many others: go/scopedtaskenvironment [1]).



 
I've found v8_test.cc but it uses `base::ThreadTaskRunnerHandle::Get()` and seems to be fine here.


That's because the corresponding test class instanciates a base::test::ScopedTaskEnvironment, which does all the initialization for you during unit-testing (have a look at its constructor code).
 
Any help is highly appreciated.

PS. I've tried to pass MessageLoop instance .task_runner() but it crashes for some reason later.
PPS. I'm not advanced C++ developer (Java/Android)

--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev...@chromium.org.
--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.
Reply all
Reply to author
Forward
0 new messages