callback function question

25 views
Skip to first unread message

all smooth

unread,
May 20, 2013, 3:50:52 AM5/20/13
to chromi...@chromium.org
This is general question regarding to Chrome code design.

During exploring on net module, there are a lot of callback functions got my attention. There are two kinds of basically, first it's messageloop->PostTask() introduced which is used for different thread. This is fine and perfect to achieve async result.
However, another very common coding practice in this module is hard for me to understand. I found there is a lot of callback assignment is the same thread and *EXECUTED* in the same thread. IO thread run time has bounch of examples:

here is one of them in net module/http/httpNetworkTransaction.cc

int HttpNetworkTransaction::DoSendRequest() {
  send_start_time_ = base::TimeTicks::Now();
  next_state_ = STATE_SEND_REQUEST_COMPLETE;

  return stream_->SendRequest(request_headers_, &response_, io_callback_);
}

This _io_callback is binding to OnIOComplete in contructor:

HttpNetworkTransaction::HttpNetworkTransaction(RequestPriority priority,
                                               HttpNetworkSession* session)
    : pending_auth_target_(HttpAuth::AUTH_NONE),
      io_callback_(base::Bind(&HttpNetworkTransaction::OnIOComplete,


They are executed in the same thread. So I feel confuse why is there a need for a callback here since it doesn't benefit execution. Is is by design, and feel neat with this way?
To me it doesn't looks like it's necessary since we know (in Chrome) it will execute in the same thread, whatever it will be blocking call...It makes code hard to understand. 

Side question: seems in each class it only contains one callback function variable like callback_ to handle different registration. This is also hard to image in DoCallback function how each caller know when should call it without know the details and get meaningful results. 
 For example, in one class definition, there are many methods will call DoCallback(), and internally it will use callback_ to handle it. But how do I know when (write program)  this callback_ is my interested one. If use clear function like instance->method which is previously binded to callback_, then it's more clear to developer. There must be very concrete reason for this, I guess. BTW, what's the design pattern name here?


Thanks for any input!

All smooth...

Joao da Silva

unread,
May 20, 2013, 5:03:37 AM5/20/13
to guang...@gmail.com, Chromium-dev
On Mon, May 20, 2013 at 9:50 AM, all smooth <guang...@gmail.com> wrote:
This is general question regarding to Chrome code design.

During exploring on net module, there are a lot of callback functions got my attention. There are two kinds of basically, first it's messageloop->PostTask() introduced which is used for different thread. This is fine and perfect to achieve async result.
However, another very common coding practice in this module is hard for me to understand. I found there is a lot of callback assignment is the same thread and *EXECUTED* in the same thread. IO thread run time has bounch of examples:

here is one of them in net module/http/httpNetworkTransaction.cc

int HttpNetworkTransaction::DoSendRequest() {
  send_start_time_ = base::TimeTicks::Now();
  next_state_ = STATE_SEND_REQUEST_COMPLETE;

  return stream_->SendRequest(request_headers_, &response_, io_callback_);
}

This _io_callback is binding to OnIOComplete in contructor:

HttpNetworkTransaction::HttpNetworkTransaction(RequestPriority priority,
                                               HttpNetworkSession* session)
    : pending_auth_target_(HttpAuth::AUTH_NONE),
      io_callback_(base::Bind(&HttpNetworkTransaction::OnIOComplete,


They are executed in the same thread. So I feel confuse why is there a need for a callback here since it doesn't benefit execution. Is is by design, and feel neat with this way?
To me it doesn't looks like it's necessary since we know (in Chrome) it will execute in the same thread, whatever it will be blocking call...It makes code hard to understand. 


Note that the io_callback_ is being passed to stream_->SendRequest(). Basically this is asking the stream_ object (an HttpStreamBase) to send out a request, and then invoke io_callback_ when done.

As you noted this all happens on the same thread, but this allows HttpStreamBase to signal completion without directly invoking HttpNetworkTransaction::OnIOComplete. This way, the HttpBaseStream can be used by any other class, because it invokes a callback and not a specific method of another class to signal completion.

Callbacks aren't used only for async operations; they're also used to abstract operations and avoid coupling classes.

 
Side question: seems in each class it only contains one callback function variable like callback_ to handle different registration. This is also hard to image in DoCallback function how each caller know when should call it without know the details and get meaningful results. 
 For example, in one class definition, there are many methods will call DoCallback(), and internally it will use callback_ to handle it. But how do I know when (write program)  this callback_ is my interested one. If use clear function like instance->method which is previously binded to callback_, then it's more clear to developer. There must be very concrete reason for this, I guess. BTW, what's the design pattern name here?


Same reason as above: invoking instance->method directly couples the two classes, but you may want to use one of them from several other classes.

One way to decouple them is to use a callback instead of invoking the method directly. Another way is to use an abstract interface that has a virtual method, which is then overridden by each user; this is simpler than callbacks when there is more than one method invoked at the delegate class.

In both cases it's not immediately obvious which concrete class and method are being invoked, due to the abstraction. A debugger and/or grep may help here :-)

- Joao
 

Thanks for any input!

All smooth...

--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
 
 
 

all smooth

unread,
May 20, 2013, 12:16:16 PM5/20/13
to chromi...@chromium.org, guang...@gmail.com
Thanks for good explanation here.  You mentioned there is interface can be used instead of callback, I think it is where my original confusion from. Using interface is  clearer and more efficient to deal with method overloading. 

Dominic Mazzoni

unread,
May 20, 2013, 1:41:02 PM5/20/13
to guangyuan li, chromium-dev
On Mon, May 20, 2013 at 9:16 AM, all smooth <guang...@gmail.com> wrote:
Thanks for good explanation here.  You mentioned there is interface can be used instead of callback, I think it is where my original confusion from. Using interface is  clearer and more efficient to deal with method overloading. 

For simple cases, I agree that interfaces can be more clear. But when things get more complex, there are many advantages of callbacks over interfaces - if you haven't already, read the docs at the top of base/callback.h to see just how powerful they are - with argument binding, etc.

- Dominic

Tom Hudson

unread,
May 20, 2013, 1:52:51 PM5/20/13
to dmaz...@chromium.org, David Turner, guangyuan li, chromium-dev
digit@ pointed out today that the price we're paying for that power on ARM architectures is substantially higher than it is on x86; something like 50ns instead of a couple of cycles, IIRC.
Reply all
Reply to author
Forward
0 new messages