浅析应用程序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函数
}