继续探索connect方法
又是忙碌的一天,终于在22:24分的时候,可以坐下来,继续我的源码分析之路的。最近一段时间的分析,收获很大,每天都能学到非常多的新东西,很多都是之前见都没见过的内容。一定要坚持下去,大学毕业的时候,这会是一笔非常宝贵的财富。
言归正传,再次进入Connect函数:
在昨天的分析中,我们看到这个函数:
bool QInternal::activateCallbacks(Callback cb, void **parameters)
{
Q_ASSERT_X(cb >= 0, "QInternal::activateCallback()", "Callback id must be a valid id");
QInternal_CallBackTable *cbt = global_callback_table();
if (cbt && cb < cbt->callbacks.size()) {
QList<qInternalCallback> callbacks = cbt->callbacks[cb];
bool ret = false;
for (int i=0; i<callbacks.size(); ++i)
ret |= (callbacks.at(i))(parameters);
return ret;
}
return false;
}
当时没有仔细对该问题进行分析,QInternal_CallBackTable *cbt = global_callback_table();这一句中包含了很多的内容呢。
跟踪global_callback_table()函数,我们发现了如下的宏定义:
Q_GLOBAL_STATIC(QInternal_CallBackTable, global_callback_table)
#define Q_GLOBAL_STATIC(TYPE, NAME)
#define Q_GLOBAL_STATIC_INIT(TYPE, NAME) /
static QGlobalStatic<TYPE > this_##NAME = { Q_BASIC_ATOMIC_INITIALIZER(0), false }
#define Q_GLOBAL_STATIC(TYPE, NAME) /
Q_GLOBAL_STATIC_INIT(TYPE, NAME); /
static TYPE *NAME() /
{ /
if (!this_##NAME.pointer && !this_##NAME.destroyed) { /
TYPE *x = new TYPE; /
if (!this_##NAME.pointer.testAndSetOrdered(0, x)) /
delete x; /
else /
static QGlobalStaticDeleter<TYPE > cleanup(this_##NAME); /
} /
return this_##NAME.pointer; /
}
将这三个宏连接起来看,我们会得到如下代码:
typedef bool (*qInternalCallback)(void **);
struct QInternal_CallBackTable {
QVector<QList<qInternalCallback> > callbacks;
};
// forward declaration, since qatomic.h needs qglobal.h
template <typename T> class QBasicAtomicPointer;//原子指针
// POD for Q_GLOBAL_STATIC
template <typename T>
class QGlobalStatic
{
public:
QBasicAtomicPointer<T> pointer;
bool destroyed;
};
Static QGlobalStatic<QInternal_CallBackTable> this_global_callback_table = { Q_BASIC_ATOMIC_INITIALIZER(0), false }//这里生成了函数指针的一个模板类,同时保证了线程安全。
static QInternal_CallBackTable * global_callback_table ()
{
if (!this_global_callback_table.pointer &&
!this_ global_callback_table.pointer.destroyed) {
QInternal_CallBackTable *x = new QInternal_CallBackTable;
if (!this_global_callback_table.pointer.testAndSetOrdered(0, x))
delete x;
else
static QGlobalStaticDeleter< QInternal_CallBackTable > cleanup this_global_callback_table);
}
Return this_global_callback_table.pointer;
}
将宏定义转换为真正的编码后,我们看到,这里首先定义了全局的指针对象,随后创建了内部回调函数表对象的指针,最后返回。
if (cbt && cb < cbt->callbacks.size()) {
QList<qInternalCallback> callbacks = cbt->callbacks[cb];
bool ret = false;
for (int i=0; i<callbacks.size(); ++i)
ret |= (callbacks.at(i))(parameters);
return ret;
}
首先查找了指定的回调函数,通过这个方法:cbt->callbacks[cb],cb在这里的值是:QInternal::ConnectCallback,但是目前想不到什么办法来查找这个回调函数的创建位置,进行了全局的搜索,调用QInternal::registerCallback该方法进行注册的地方只有一个,而且不是注册QInternal::ConnectCallback这个回调函数,所以不知道该如何查找下去了……
接下来的这个操作,循环执行了所有的回调函数,这些回调函数的指针是在调用registerCallback的时候创建出来的。
#ifndef QT_NO_DEBUG
bool warnCompat = true;
#endif
if (type == Qt::AutoCompatConnection) {
type = Qt::AutoConnection;
#ifndef QT_NO_DEBUG
warnCompat = false;
#endif
}
这里针对调试环境做了一些设置,现在还不能理解其中的含义,继续往下看。
if (sender == 0 || receiver == 0 || signal == 0 || method == 0) {
qWarning("QObject::connect: Cannot connect %s::%s to %s::%s",
sender ? sender->metaObject()->className() : "(null)",
(signal && *signal) ? signal+1 : "(null)",
receiver ? receiver->metaObject()->className() : "(null)",
(method && *method) ? method+1 : "(null)");
return false;
}
这里判断了信号的有效性,我们应该注意到,这里对这些参数判断之前,进入了连接的回调函数,也就是说,具体的判断应该是在ConnectCallback中进行的。
接下来是:
if (!check_signal_macro(sender, signal, "connect", "bind"))
return false;
对这个函数进行跟踪,发现其作用是判断这个信号或者槽之前的标志(0、1、2)是否正确。
接下来是对信号函数的检索:
/*! /internal
Same as QMetaObject::indexOfSignal, but the result is the local offset to the base object.
/a baseObject will be adjusted to the enclosing QMetaObject, or 0 if the signal is not found
*/
int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject, const char *signal)
{
int i = -1;
while (*baseObject) {
const QMetaObject *const m = *baseObject;
for (i = priv(m->d.data)->methodCount-1; i >= 0; --i)
if ((m->d.data[priv(m->d.data)->methodData + 5*i + 4] & MethodTypeMask) == MethodSignal
&& strcmp(signal, m->d.stringdata
+ m->d.data[priv(m->d.data)->methodData + 5*i]) == 0) {
break;
}
if (i >= 0)
break;
*baseObject = m->d.superdata;
}
#ifndef QT_NO_DEBUG
const QMetaObject *m = *baseObject;
if (i >= 0 && m && m->d.superdata) {
int conflict = m->d.superdata->indexOfMethod(signal);
if (conflict >= 0)
qWarning("QMetaObject::indexOfSignal:%s: Conflict with %s::%s",
m->d.stringdata, m->d.superdata->d.stringdata, signal);
}
#endif
return i;
}
接下来的环节比较复杂,今天是分析不完了,时间不早了,也该去睡觉了,明天继续。
2009年10月20日星期二 23:44