Chinaunix首页 | 论坛 | 博客
  • 博客访问: 680549
  • 博文数量: 404
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 1237
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-03 10:45
文章分类

全部博文(404)

文章存档

2017年(1)

2016年(27)

2015年(39)

2014年(55)

2013年(66)

2012年(216)

分类: LINUX

2016-07-04 15:16:54

浅析应用程序dbus_bus_get函数在lib库中的实际执行流程
《浅析dbus-session后台daemon如何处理client们发送过来的mesage》
《浅析如何从内存中读取解析dbus系统connection相关信息》

如果打算使用dbus进行数据传输,那么第一步要做的就是执行dbus_bus_get,
将自己注册到dbus总线上,与dbus建立一个connection连接,让dbus知道自己打算存在,
然后dbus内核将执行实际创建动作,如果自己的申请不过分,那么dbus将真的让你自己存在,
其他同样注册登记到dbus的应用程序就可以向你自己发送数据了,dbus内核会作数据中转工作.

conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
DBusConnection *
dbus_bus_get (DBusBusType  type,
          DBusError   *error)
{
  return internal_bus_get (type, FALSE, error);
}

static DBusConnection *
internal_bus_get (DBusBusType  type,
                  dbus_bool_t  private,
                  DBusError   *error)
{
  const char *address;
  DBusConnection *connection;
  BusData *bd;
  DBusBusType address_type;

  _dbus_return_val_if_fail (type >= 0 && type < N_BUS_TYPES, NULL);
  _dbus_return_val_if_error_is_set (error, NULL);

  _DBUS_LOCK (bus);

  if (!init_connections_unlocked ())
// 如果第一次执行init_connections_unlocked,那么将执行如下初始化操作:
// 从环境变量中读取DBUS_BUS_SYSTEM﹑DBUS_BUS_SESSION和DBUS_BUS_STARTER数值,
// 他们分别对应"DBUS_SYSTEM_BUS_ADDRESS"﹑"DBUS_SESSION_BUS_ADDRESS"和"DBUS_STARTER_ADDRESS"
// 如果没有发现环境变量,那么使用默认值,如果"DBUS_STARTER_ADDRESS"不存在,
// 那么使用"DBUS_SESSION_BUS_ADDRESS"环境变量值我的ubuntu-8.10下,
// env只有"DBUS_SESSION_BUS_ADDRESS"一个赋值变量,其值如下:
// DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-tzodgj8z66,guid=0012677c77111c589885306d4a3c1c64
// 之后
// 1._dbus_setenv ("DBUS_ACTIVATION_ADDRESS", NULL)
// 2._dbus_setenv ("DBUS_ACTIVATION_BUS_TYPE", NULL)
// 3._dbus_register_shutdown_func (addresses_shutdown_func, NULL)
/*
dbus_bool_t
_dbus_register_shutdown_func (DBusShutdownFunction  func,
                              void                 *data)
{
  ShutdownClosure *c;

  c = dbus_new (ShutdownClosure, 1);

  if (c == NULL)
    return FALSE;

  c->func = func;
  c->data = data;

  _DBUS_LOCK (shutdown_funcs);
 
  c->next = registered_globals; // 挂接到registered_globals全局链表上,当shut_down时会调用链表上的所有注册函数.
  registered_globals = c;

  _DBUS_UNLOCK (shutdown_funcs);
 
  return TRUE;
}
void
dbus_shutdown (void)
{
  while (registered_globals != NULL)
    {
      ShutdownClosure *c;

      c = registered_globals;
      registered_globals = c->next;
     
      (* c->func) (c->data);
     
      dbus_free (c);
    }

  _dbus_current_generation += 1;
}
*/
// 最后initialized = TRUE;就ok了.
    {
      _DBUS_UNLOCK (bus);
      _DBUS_SET_OOM (error);
      return NULL;
    }

  /* We want to use the activation address even if the
   * activating bus is the session or system bus,
   * per the spec.
   */
  address_type = type;
 
  /* Use the real type of the activation bus for getting its
   * connection, but only if the real type's address is available. (If
   * the activating bus isn't a well-known bus then
   * activation_bus_type == DBUS_BUS_STARTER)
   */
  if (type == DBUS_BUS_STARTER &&
      bus_connection_addresses[activation_bus_type] != NULL)
    type = activation_bus_type;
 
  if (!private && bus_connections[type] != NULL)
    {
      // 因为应用程序刚刚启动,所以bus_connections[type]为NULL,不会执行到这里
      connection = bus_connections[type];
      dbus_connection_ref (connection);
     
      _DBUS_UNLOCK (bus);
      return connection;
    }
// 从env中读取到的数值
// DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-tzodgj8z66,guid=0012677c77111c589885306d4a3c1c64
  address = bus_connection_addresses[address_type];
  if (address == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_FAILED,
                      "Unable to determine the address of the message bus (try 'man dbus-launch' and 'man dbus-daemon' for help)");
      _DBUS_UNLOCK (bus);
      return NULL;
    }

  if (private)
    connection = dbus_connection_open_private (address, error);
  else
    // 建立一个connection,
    // 该connection->watches链表上登记了需要被poll()监控的
    // 与/tmp/dbus-tzodgj8z66通道发生数据流动的read_watch和write_watch单元
    // 但尚未添加到loop中[luther.gliethttp].
    connection = dbus_connection_open (address, error); // 外部应用程序调用该函数创建一个connection,源码见后
 
  if (!connection)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      _DBUS_UNLOCK (bus);
      return NULL;
    }

  if (!dbus_bus_register (connection, error)) // 向总线注册这个connection连接,源码见后面.
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      _dbus_connection_close_possibly_shared (connection);
      dbus_connection_unref (connection);

      _DBUS_UNLOCK (bus);
      return NULL;
    }

  if (!private)
    {
      /* store a weak ref to the connection (dbus-connection.c is
       * supposed to have a strong ref that it drops on disconnect,
       * since this is a shared connection)
       */
      bus_connections[type] = connection;
    }

  /* By default we're bound to the lifecycle of
   * the message bus.
   */
  dbus_connection_set_exit_on_disconnect (connection,
                                          TRUE);
 
  _DBUS_LOCK (bus_datas);
  bd = ensure_bus_data (connection);
  _dbus_assert (bd != NULL); /* it should have been created on
                                register, so OOM not possible */
  bd->is_well_known = TRUE;
  _DBUS_UNLOCK (bus_datas);

 
  _DBUS_UNLOCK (bus);

  /* Return a reference to the caller */
  return connection;
}

DBusConnection*
dbus_connection_open (const char     *address,
                      DBusError      *error)
{
  DBusConnection *connection;

  _dbus_return_val_if_fail (address != NULL, NULL);
  _dbus_return_val_if_error_is_set (error, NULL);

  connection = _dbus_connection_open_internal (address,
                                               TRUE, // shared
                                               error);

  return connection;
}
static DBusConnection*
_dbus_connection_open_internal (const char     *address,
                                dbus_bool_t     shared,
                                DBusError      *error)
{
  DBusConnection *connection;
  DBusAddressEntry **entries;
  DBusError tmp_error = DBUS_ERROR_INIT;
  DBusError first_error = DBUS_ERROR_INIT;
  int len, i;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  _dbus_verbose ("opening %s connection to: %s\n",
                 shared ? "shared" : "private", address);
 
  // 分解地址字符串:unix:abstract=/tmp/dbus-tzodgj8z66,guid=0012677c77111c589885306d4a3c1c64
  // len等于1,entries[0]的key链表上包含2个值,它们共用的method为unix,
  // key1等于abstract,value为/tmp/dbus-tzodgj8z66
  // key2等于guid,value为0012677c77111c589885306d4a3c1c64
  if (!dbus_parse_address (address, &entries, &len, error))
    return NULL;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
  connection = NULL;

  for (i = 0; i < len; i++)
    {
      if (shared)
        {
          if (!connection_lookup_shared (entries[i], &connection))
// 首先检查作为hash table的shared_connections是否NULL,因为我们这是第1次进入,所以一定为NULL,
// 申请hash table空间,注册_dbus_register_shutdown_func (shared_connections_shutdown, NULL)释放内存函数
// 如果不是第1次进入,那么将首先
// guid = dbus_address_entry_get_value (entry, "guid"); //读取entries[i]的"guid" key,如果存在
// 检查字符串0012677c77111c589885306d4a3c1c64是否已经在hash表中了,即该value对应的connection是否已经存在了.
// connection = _dbus_hash_table_lookup_string (shared_connections, guid);
// _dbus_hash_table_lookup_string仅仅是查询hash表中是否已经登记了该guid值,如够没有,并不自动添件到hash表中
            _DBUS_SET_OOM (&tmp_error);
        }

      if (connection == NULL)
        {
          connection = connection_try_from_address_entry (entries[i], // 源码见下面,
          // 建立一个connection,
          // 该connection->watches链表上登记了需要被poll()监控的
          // 与/tmp/dbus-tzodgj8z66通道是否发生数据流动的read_watch和write_watch单元
          // 但尚未添加到loop中[luther.gliethttp].
                                                          &tmp_error);

          if (connection != NULL && shared)
            {
              const char *guid;
                 
              connection->shareable = TRUE;
                 
              /* guid may be NULL */
              guid = dbus_address_entry_get_value (entries[i], "guid");
                 
              CONNECTION_LOCK (connection);
         
              if (!connection_record_shared_unlocked (connection, guid))
            // 将0012677c77111c589885306d4a3c1c64添加到shared_connections[]这个hash表中
            // key键值0012677c77111c589885306d4a3c1c64对应的数据为connection指针地址[luther.gliethttp]
            // 同时connection->server_guid = guid_in_connection;这样DBUS_SESSION_BUS_ADDRESS就成了
            // 应用程序发生connection连接的server_guid.[luther.gliethttp]
                {
                  _DBUS_SET_OOM (&tmp_error);
                  _dbus_connection_close_possibly_shared_and_unlock (connection);
                  dbus_connection_unref (connection);
                  connection = NULL;
                }
              else
                CONNECTION_UNLOCK (connection);
            }
        }
     
      if (connection)
        break;

      _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
     
      if (i == 0)
        dbus_move_error (&tmp_error, &first_error);
      else
        dbus_error_free (&tmp_error);
    }
 
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
 
  if (connection == NULL)
    {
      _DBUS_ASSERT_ERROR_IS_SET (&first_error);
      dbus_move_error (&first_error, error);
    }
  else
    dbus_error_free (&first_error);
 
  dbus_address_entries_free (entries);
  return connection;
}

static DBusConnection*
connection_try_from_address_entry (DBusAddressEntry *entry,
                                   DBusError        *error)
{
  DBusTransport *transport;
  DBusConnection *connection;

  transport = _dbus_transport_open (entry, error);
// 源码见下面[仅仅打开一个transport,指向/tmp/dbus-tzodgj8z66的unix类型通信管道luther.gliethttp]
// 同时创建与/tmp/dbus-tzodgj8z66连接的fd句柄对应的read_watch和write_watch

  if (transport == NULL)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      return NULL;
    }

  connection = _dbus_connection_new_for_transport (transport);
  // 可以参考《浅析dbus server接收一个client连接具体流程》
  // http://blog.chinaunix.net/u1/38994/showart_1963787.html
  // 为该transport通信通道连接建立connection维护信息[luther.gliethttp]
  // _dbus_connection_new_for_transport
  // ==>_dbus_transport_set_connection (transport, connection)
  //    将与/tmp/dbus-tzodgj8z66连接的socket_transport->write_watch和read_watch添加到context->loop中,
  //    最后会被添加到loop循环的poll()中.
  // ==*>(* transport->vtable->connection_set) (transport)
  //    即:socket_vtable.socket_connection_set()
  // ==*>socket_connection_set
  // ==**>设置向/tmp/dbus-tzodgj8z66发送数据和接收到数据后处理回调函数_dbus_connection_handle_watch
  //    将socket_transport->write_watch和read_watch添加到connection->watches链表中.
  _dbus_transport_unref (transport);
 
  if (connection == NULL)
    {
      _DBUS_SET_OOM (error);
      return NULL;
    }

#ifndef DBUS_DISABLE_CHECKS
  _dbus_assert (!connection->have_connection_lock);
#endif
  return connection;
}
DBusTransport*
_dbus_transport_open (DBusAddressEntry *entry,
                      DBusError        *error)
{
  DBusTransport *transport;
  const char *expected_guid_orig;
  char *expected_guid;
  int i;
  DBusError tmp_error = DBUS_ERROR_INIT;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
  transport = NULL;
  expected_guid_orig = dbus_address_entry_get_value (entry, "guid");
  expected_guid = _dbus_strdup (expected_guid_orig); // dup字符串0012677c77111c589885306d4a3c1c64

  if (expected_guid_orig != NULL && expected_guid == NULL)
    {
      _DBUS_SET_OOM (error);
      return NULL;
    }

  for (i = 0; i < (int) _DBUS_N_ELEMENTS (open_funcs); ++i)
    {
      DBusTransportOpenResult result;

      _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
      // 将使用open_funcs方法数组中的_dbus_transport_open_platform_specific函数打开method为unix的通信管道
      // _dbus_transport_open_platform_specific
      // ==>_dbus_transport_new_for_domain_socket
      // ==>_dbus_transport_new_for_socket // 仅仅创建一个transport
      result = (* open_funcs[i].func) (entry, &transport, &tmp_error);

      switch (result)
        {
        case DBUS_TRANSPORT_OPEN_OK:
          _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
          goto out;
          break;
        case DBUS_TRANSPORT_OPEN_NOT_HANDLED:
          _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
          /* keep going through the loop of open funcs */
          break;
        case DBUS_TRANSPORT_OPEN_BAD_ADDRESS:
          _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
          goto out;
          break;
        case DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT:
          _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
          goto out;
          break;
        }
    }

 out:
 
  if (transport == NULL)
    {
      if (!dbus_error_is_set (&tmp_error))
        _dbus_set_bad_address (&tmp_error,
                               NULL, NULL,
                               "Unknown address type (examples of valid types are \"tcp\" and on UNIX \"unix\")");
     
      _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
      dbus_move_error(&tmp_error, error);
      dbus_free (expected_guid);
    }
  else
    {
      _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);

      /* In the case of autostart the initial guid is NULL
       * and the autostart transport recursively calls
       * _dbus_open_transport wich returns a transport
       * with a guid.  That guid is the definitive one.
       *
       * FIXME: if more transports are added they may have
       * an effect on the expected_guid semantics (i.e.
       * expected_guid and transport->expected_guid may
       * both have values).  This is very unlikely though
       * we should either throw asserts here for those
       * corner cases or refactor the code so it is
       * clearer on what is expected and what is not
       */
      if(expected_guid)
        transport->expected_guid = expected_guid; // 对应guid字符串0012677c77111c589885306d4a3c1c64
    }

  return transport;
}

// 向总线注册这个connection连接
dbus_bool_t
dbus_bus_register (DBusConnection *connection,
                   DBusError      *error)
{
  DBusMessage *message, *reply;
  char *name;
  BusData *bd;
  dbus_bool_t retval;

  _dbus_return_val_if_fail (connection != NULL, FALSE);
  _dbus_return_val_if_error_is_set (error, FALSE);

  retval = FALSE;

  _DBUS_LOCK (bus_datas);

  bd = ensure_bus_data (connection);
  if (bd == NULL)
    {
      _DBUS_SET_OOM (error);
      _DBUS_UNLOCK (bus_datas);
      return FALSE;
    }

  if (bd->unique_name != NULL)
    {
      _dbus_verbose ("Ignoring attempt to register the same DBusConnection %s with the message bus a second time.\n",
                     bd->unique_name);
      _DBUS_UNLOCK (bus_datas);

      /* Success! */
      return TRUE;
    }
 
  // 可以参考《浅析dbus_message_new_signal()函数内部具体实现》
  // http://blog.chinaunix.net/u1/38994/showart_1959557.html
  // #define DBUS_SERVICE_DBUS      "org.freedesktop.DBus"
  // #define DBUS_PATH_DBUS  "/org/freedesktop/DBus"
  // #define DBUS_INTERFACE_DBUS           "org.freedesktop.DBus"
  // 该message将发送给"org.freedesktop.DBus"
  // path为"/org/freedesktop/DBus"
  // 接口为"org.freedesktop.DBus"
  // 方法为"Hello"  -- 调用相应的方法处理函数处理该message消息
  message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                          DBUS_PATH_DBUS,
                                          DBUS_INTERFACE_DBUS,
                                          "Hello");

  if (!message)
    {
      _DBUS_SET_OOM (error);

      _DBUS_UNLOCK (bus_datas);
      return FALSE;
    }
 
  // 源码见下面
  // 等待peer发送reply回来
  reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);

  dbus_message_unref (message);
 
  if (reply == NULL)
    goto out;
  else if (dbus_set_error_from_message (error, reply))
    goto out;
  else if (!dbus_message_get_args (reply, error,
                                   DBUS_TYPE_STRING, &name, // 获取peer返回回来的unique_name数据
                                   DBUS_TYPE_INVALID))
    goto out;
 
  bd->unique_name = _dbus_strdup (name); // 将unique_name赋值给自己,这样所有工作也都完成了[luther.gliethttp]
  if (bd->unique_name == NULL)
    {
      _DBUS_SET_OOM (error);
      goto out;
    }
 
  retval = TRUE;
 
 out:
  if (reply)
    dbus_message_unref (reply);

  if (!retval)
    _DBUS_ASSERT_ERROR_IS_SET (error);

  _DBUS_UNLOCK (bus_datas);
 
  return retval;
}

DBusMessage*
dbus_connection_send_with_reply_and_block (DBusConnection     *connection,
                                           DBusMessage        *message,
                                           int                 timeout_milliseconds,
                                           DBusError          *error)
{
  DBusMessage *reply;
  DBusPendingCall *pending;
 
  _dbus_return_val_if_fail (connection != NULL, NULL);
  _dbus_return_val_if_fail (message != NULL, NULL);
  _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, NULL);
  _dbus_return_val_if_error_is_set (error, NULL);
 
  // 源码见下面
  if (!dbus_connection_send_with_reply (connection, message,
                                        &pending, timeout_milliseconds))
    {
      _DBUS_SET_OOM (error);
      return NULL;
    }

  if (pending == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Connection is closed");
      return NULL;
    }
 
  dbus_pending_call_block (pending); // 将message发送出去同时阻塞等待pending超时或者reply到来
// dbus_pending_call_block
// ==>_dbus_connection_block_pending_call
// ==*>check_for_reply_and_update_dispatch_unlocked
// ==**>complete_pending_call_and_unlock
// ==***>_dbus_pending_call_set_reply_unlocked设置了reply为message
// ==>_dbus_connection_flush_unlocked  // 执行实际发送操作,之后就等待pending描述的serial id号相等的reply消息过来.
// ==>_dbus_connection_get_dispatch_status_unlocked // 检查是否有reply消息过来
// ==>check_for_reply_and_update_dispatch_unlocked (connection, pending) // 检查incoming来的message reply是否为pending等待的serial id号,如果是,那么return ok.
// ==>_dbus_connection_do_iteration_unlocked
// ==>_dbus_transport_do_iteration
// ==>transport->vtable->do_iteration()
// ==>socket_vtable.socket_do_iteration()
// ==>socket_do_iteration
// ==>do_writing (transport);或者do_reading (transport); // 循环等待reply数据到来
  reply = dbus_pending_call_steal_reply (pending);
  // 在
  // dbus_pending_call_block
  // ==>_dbus_connection_block_pending_call
  // ==>check_for_reply_and_update_dispatch_unlocked
  // ==>complete_pending_call_and_unlock
  // ==>_dbus_pending_call_set_reply_unlocked设置了reply为message
  dbus_pending_call_unref (pending);
// 好了数据发送出去了,现在返回回来了,可能是超时,可能是对端peer发送过来了真正的reply[luther.gliethttp]
  /* call_complete_and_unlock() called from pending_call_block() should
   * always fill this in.
   */
  _dbus_assert (reply != NULL);
 
   if (dbus_set_error_from_message (error, reply))
    {
      dbus_message_unref (reply);
      return NULL;
    }
  else
    return reply;
}

dbus_bool_t
dbus_connection_send_with_reply (DBusConnection     *connection,
                                 DBusMessage        *message,
                                 DBusPendingCall   **pending_return,
                                 int                 timeout_milliseconds)
{
  DBusPendingCall *pending;
  dbus_int32_t serial = -1;
  DBusDispatchStatus status;

  _dbus_return_val_if_fail (connection != NULL, FALSE);
  _dbus_return_val_if_fail (message != NULL, FALSE);
  _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE);

  if (pending_return)
    *pending_return = NULL;

  CONNECTION_LOCK (connection);

   if (!_dbus_connection_get_is_connected_unlocked (connection))
    {
      CONNECTION_UNLOCK (connection);

      return TRUE;
    }
// 创建一个对应该connection的pending内存空间,设置超时回调函数reply_handler_timeout
// 和超时时间timeout_milliseconds,如果时间为-1,那么将赋予25秒默认值[luther.gliethttp]
  pending = _dbus_pending_call_new_unlocked (connection,
                                             timeout_milliseconds,
                                             reply_handler_timeout);

  if (pending == NULL)
    {
      CONNECTION_UNLOCK (connection);
      return FALSE;
    }

  /* Assign a serial to the message */
  serial = dbus_message_get_serial (message); // 获取serial号,以便reply到来之后,区分发送出去的消息
  if (serial == 0) // dbus_message_new_method_call创建时默认值就是0
    {
      serial = _dbus_connection_get_next_client_serial (connection);
      // 那么使用connection->client_serial++;单向递增作为serial号,作为message reply的唯一判断id[luther.gliethttp]
      dbus_message_set_serial (message, serial); // 将获得的serial回写到header->data[SERIAL_OFFSET]空间[luther.gliethttp]
    }

// 设置pending->reply_serial = serial;
// reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY,...); // 设置超时处理函数使用到的结构体
// pending->timeout_link = reply_link; // 添加到超时链表上
  if (!_dbus_pending_call_set_timeout_error_unlocked (pending, message, serial))
    goto error;
   
  /* Insert the serial in the pending replies hash;
   * hash takes a refcount on DBusPendingCall.
   * Also, add the timeout.
   */
// 源码见后面
// 将自己添加到connection->pending_replies中,这样就只需等待reply数据到来或者timeout超时就行了[luther.gliethttp]
// 然后从reply中提取出reply_serial,通过hash计算读取到pending,就可以了,
// 冲突是通过reply的reply_serial数值与entry->key相等来解决的.
  if (!_dbus_connection_attach_pending_call_unlocked (connection,
                              pending))
    goto error;
 
  if (!_dbus_connection_send_unlocked_no_update (connection, message, NULL)) // 源码见下面
    {
      _dbus_connection_detach_pending_call_and_unlock (connection,
                               pending);
      goto error_unlocked;
    }

  if (pending_return) // 返回pending
    *pending_return = pending; /* hand off refcount */
  else
    {
      _dbus_connection_detach_pending_call_unlocked (connection, pending);
      /* we still have a ref to the pending call in this case, we unref
       * after unlocking, below
       */
    }

  status = _dbus_connection_get_dispatch_status_unlocked (connection);

  /* this calls out to user code */
  _dbus_connection_update_dispatch_status_and_unlock (connection, status);
  // 调用dispatch_status_function将connection添加到loop->need_dispatch中

  if (pending_return == NULL)
    dbus_pending_call_unref (pending);
 
  return TRUE; // ok.

 error:
  CONNECTION_UNLOCK (connection);
 error_unlocked:
  dbus_pending_call_unref (pending);
  return FALSE;
}

static dbus_bool_t
_dbus_connection_attach_pending_call_unlocked (DBusConnection  *connection,
                                               DBusPendingCall *pending)
{
  dbus_uint32_t reply_serial;
  DBusTimeout *timeout;

  HAVE_LOCK_CHECK (connection);

  reply_serial = _dbus_pending_call_get_reply_serial_unlocked (pending); // 获取serial

  _dbus_assert (reply_serial != 0);

  timeout = _dbus_pending_call_get_timeout_unlocked (pending); // 获取pending结构体创建时申请到的timeout

  if (!_dbus_connection_add_timeout_unlocked (connection, timeout)) // 将timeout添加到connection->timeouts链表中
// 在loop中,dbus会添加到poll()中.
    return FALSE;
// 将自己添加到connection->pending_replies中,这样就只需等待reply数据到来或者timeout超时就行了[luther.gliethttp]
// 然后从reply中提取出reply_serial,通过hash计算读取到pending,就可以了,
// 冲突是通过reply的reply_serial数值与entry->key相等来解决的.
  if (!_dbus_hash_table_insert_int (connection->pending_replies, // 执行find_direct_function函数添加
                                    reply_serial, // key
                                    pending)) // value
/*
static DBusHashEntry*
find_direct_function (DBusHashTable        *table,
                      void                 *key,
                      dbus_bool_t           create_if_not_found,
                      DBusHashEntry      ***bucket,
                      DBusPreallocatedHash *preallocated)
{
  unsigned int idx;
 
  idx = RANDOM_INDEX (table, key) & table->mask; // 将线性的serial数据打散,打散算法为简单的乘一个常数,如下:
//#define RANDOM_INDEX(table, i)(((((long) (i))*1103515245) >> (table)->down_shift) & (table)->mask)


  return find_generic_function (table, key, idx,
                                NULL, create_if_not_found, bucket,
                                preallocated);
}
*/
    {
      _dbus_connection_remove_timeout_unlocked (connection, timeout);

      _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE);
      HAVE_LOCK_CHECK (connection);
      return FALSE;
    }
 
  _dbus_pending_call_set_timeout_added_unlocked (pending, TRUE);

  _dbus_pending_call_ref_unlocked (pending); // 该pending的引用++.

  HAVE_LOCK_CHECK (connection);
 
  return TRUE;
}

_dbus_connection_send_unlocked_no_update (DBusConnection *connection,
                                          DBusMessage    *message,
                                          dbus_uint32_t  *client_serial)
{
  DBusPreallocatedSend *preallocated;

  _dbus_assert (connection != NULL);
  _dbus_assert (message != NULL);
 
  // 从connection->link_cache获取preallocated->queue_link或者preallocated->counter_link
  // 或者从mem_pool中malloc
  // 1.preallocated->queue_link
  // 2.preallocated->counter_link
  // preallocated->connection = connection;
  preallocated = _dbus_connection_preallocate_send_unlocked (connection);
  if (preallocated == NULL)
    return FALSE;

  _dbus_connection_send_preallocated_unlocked_no_update (connection,
                                                         preallocated,
                                                         message,
                                                         client_serial);
  return TRUE;
}

static void
_dbus_connection_send_preallocated_unlocked_no_update (DBusConnection       *connection,
                                                       DBusPreallocatedSend *preallocated,
                                                       DBusMessage          *message,
                                                       dbus_uint32_t        *client_serial)
{
  dbus_uint32_t serial;
  const char *sig;

  preallocated->queue_link->data = message; // queue_link的data域数值为message
  _dbus_list_prepend_link (&connection->outgoing_messages,
// 将queue_link添加到connection->outgoing_messages待发信息队列头部[luther.gliethttp]
                           preallocated->queue_link);

// 将preallocated->counter_link添加到message->size_counters链表尾部
// preallocated->counter_link->value中存放了message->header和body数据长度累计[luther.gliethtpt]
  _dbus_message_add_size_counter_link (message,
                                       preallocated->counter_link);

  dbus_free (preallocated);
  preallocated = NULL;
 
  dbus_message_ref (message); // message内存块引用计数原子操作++
 
  connection->n_outgoing += 1; // outgoing个数加1,又多了一个待发送的message[luther.gliethttp]

  sig = dbus_message_get_signature (message);
 
  if (dbus_message_get_serial (message) == 0)
    {
      serial = _dbus_connection_get_next_client_serial (connection);
      dbus_message_set_serial (message, serial);
      if (client_serial)
        *client_serial = serial;
    }
  else
    {
      if (client_serial)
        *client_serial = dbus_message_get_serial (message);
    }

  _dbus_verbose ("Message %p serial is %u\n",
                 message, dbus_message_get_serial (message));
 
  // 源码见下面
  dbus_message_lock (message);

  /* Now we need to run an iteration to hopefully just write the messages
   * out immediately, and otherwise get them queued up
   */
  _dbus_connection_do_iteration_unlocked (connection,
                                          DBUS_ITERATION_DO_WRITING,
                                          -1);

  /* If stuff is still queued up, be sure we wake up the main loop */
  if (connection->n_outgoing > 0)
    _dbus_connection_wakeup_mainloop (connection); // 唤醒mainloop
}

void
dbus_message_lock (DBusMessage  *message)
{
  if (!message->locked)
    {
        // 将消息body长度填入header相应域
      _dbus_header_update_lengths (&message->header,
                                   _dbus_string_get_length (&message->body));

      /* must have a signature if you have a body */
      _dbus_assert (_dbus_string_get_length (&message->body) == 0 ||
                    dbus_message_get_signature (message) != NULL);

      message->locked = TRUE; // ok,完了
    }
}

static void
_dbus_connection_wakeup_mainloop (DBusConnection *connection)
{
  if (connection->wakeup_main_function) // NULL数值
    (*connection->wakeup_main_function) (connection->wakeup_main_data);
    //
    //dbus_connection_set_wakeup_main_function
    //==>设置connection->wakeup_main_function函数
}
阅读(4052) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~