GLib/GIO 事件源、异步方法与线程的关系

事件源与线程的关系
事件源可以在任意线程中创建并可以 Attach 到任意的线程主上下文(GMainContext)上,Callback 由 Attach 的主线程上下文对应的线程调用。

异步方法与线程的关系
在 GIO 中,一个异步方法通常有两个类型的方法,分别是以 _async 和 _finish 结尾的。_async 方法用于发起一个异步调用,而 _finish 用于取得异步调用的结果。异步方法是使用线程实现的,大概的逻辑是一个线程在 _async 方法中创建新的线程,新线程执行一个事务,完成后通过一定的方法将结果通知给调用线程,调用线程再调用 _finish 方法取得异步方法的结果。

在 GLib 系统中,每个线程都有其主上下文(GMainContext),在一个线程中(主线程或其它线程)调用对象 _async 方法后,会创建一个 GSimpleAsyncResult 类型的对象,该对象用于保存和在调用线程与执行线程间传递数据。接着将方法调用需要的数据(即 _async 方法的参数)“打包“在一个结构体的实例中并设置到 GSimpleAsyncResult 的对象中保存。然后,会调用 g_simple_async_result_run_in_thread 方法并传入一个线程处理函数,该方法通过 GIOSchedulerJob 创建一个新的线程(通过一个专门的线程池),并执行传入的线程处理函数。当线程处理函数执行完成后,会将结果数据保存在 GSimpleAsyncResult 对象中(线程处理函数中实现)。接着会创建一个 GIldeSource 并 Attach 到调用 _async 方法的线程主上下文中,此事件源的 Callback 中会调用 _async 方法中传入的 GAsyncReadyCallback(由调用 _async 方法的线程调用)。最后,应该在 GAsyncReadyCallback 中调用对象的 _finish 方法取得异步调用的结果。

测试程序

/* async.c
 * Heiher <admin@heiher.info>
 * gcc -o async async.c `pkg-config --cflags --libs gio-2.0`
 */
 
#include <gio/gio.h>
 
void enumerate_children_handler (GObject *obj,
			GAsyncResult *res, gpointer user_data)
{
	GFileEnumerator *enumerator = NULL;
 
	enumerator = g_file_enumerate_children_finish (G_FILE (obj),
				res, NULL);
	g_file_enumerator_close_async (enumerator, G_PRIORITY_DEFAULT,
				NULL, NULL, NULL);
	g_object_unref (enumerator);
 
	g_debug ("Handler Thread: %p", g_thread_self ());
}
 
gboolean source_handler (gpointer user_data)
{
	g_debug ("Source Thread: %p", g_thread_self ());
 
	return FALSE;
}
 
gpointer thread_handler (gpointer data)
{
	GMainContext *context = data;
	GSource *source = NULL;
 
	g_debug ("Test Thread: %p", g_thread_self ());
 
	source = g_idle_source_new ();
	g_source_set_priority (source, G_PRIORITY_DEFAULT);
	g_source_set_callback (source, source_handler, NULL, NULL);
	g_source_attach (source, context);
	g_source_unref (source);
 
	return FALSE;
}
 
int main (int argc, char *argv[])
{
	GMainLoop *main_loop = NULL;
 
	g_type_init ();
 
	main_loop = g_main_loop_new (NULL, FALSE);
	if (main_loop) {
		GFile *file = NULL;
 
		file = g_file_new_for_path ("/usr/lib");
 
		g_debug ("Main Thread: %p", g_thread_self ());
 
		g_file_enumerate_children_async (file,
					G_FILE_ATTRIBUTE_STANDARD_NAME,
					G_FILE_QUERY_INFO_NONE,
					G_PRIORITY_DEFAULT,
					NULL,
					enumerate_children_handler,
					NULL);
 
		g_thread_new ("Test", thread_handler,
					g_main_context_default ());
 
		g_main_loop_run (main_loop);
 
		g_object_unref (file);
 
		g_main_loop_unref (main_loop);
	}
 
	return 0;
}

运行结果

** (process:22820): DEBUG: Main Thread: 0x1aa4ca0
** (process:22820): DEBUG: Test Thread: 0x1adac50
** (process:22820): DEBUG: Source Thread: 0x1aa4ca0
** (process:22820): DEBUG: Handler Thread: 0x1aa4ca0

Over!

提升 QEMU 中 MIPS-Malta 机器的 RAM 容量上限

目前 QEMU 中 MIPS-Malta 机器的 RAM 容量被限制在了最高 256M,原因是其外围设备被映射在了物理地址空间的 0x10000000 – 0x20000000 之间。为了使用更多的 RAM,需要同时修改机器的“硬件”配置和内核中的地址空间映射表来使用高端内存。为此需要使用 MIPS-5Kf 处理器且需要使用64位的内核,因为要访问 0x20000000 之后的物理地址空间。

在 QEMU 中,当 RAM 配置 <= 256M 时,只使用低 256M物理地址空间来映射;当 RAM 配置 > 256M 时,将其余部分映射到 0x20000000 之后,配置为:

0x00000000 - 0x0fffffff => RAM
0x10000000 - 0x1fffffff => 设备
0x20000000 -            => RAM

在 内核 中,增加一个内存映射表项,来标记 0x20000000 – 0x? 为 BOOT_MEM_RAM。

QEMU 补丁 => https://github.com/heiher/hev-patches/blob/master/qemu/qemu-mips-malta.diff
Kernel 补丁 => https://github.com/heiher/hev-patches/blob/master/linux/mips-malta.diff
Kernel 配置 => http://heiher.info/sftp/files/config.malta

目前,最高可设置为 2047M 的 RAM。

Over!

Vala 1.7.7 类关系表

class vala.CodeVisitor
  class vala.FlowAnalyzer
  class vala.Genie.Parser
  class vala.GirParser
  class vala.Parser
  class vala.SemanticAnalyzer
  class vala.SymbolResolver
  class vala.CodeWriter
  class vala.CodeGenerator
    class codegen.CCodeBaseModule
  	  class codegen.CCodeStructModule
  	    class codegen.CCodeMethodModule
  	      class codegen.CCodeControlFlowModule
  	        class codegen.CCodeMemberAccessModule
  	          class codegen.CCodeAssignmentModule
  	            class codegen.CCodeMethodCallModule
  	              class codegen.CCodeArrayModule
  	                class codegen.CCodeDelegateModule
  	                  class codegen.GErrorModule
  	                    class codegen.GTypeModule
  	                      class codegen.GObjectModule
  	                        class codegen.GSignalModule
  	                          class codegen.GAsyncModule
  	                            class codegen.GVariantModule
  	                              class codegen.GDBusModule
  	                                class codegen.GDBusClientModule
  	                                  class codegen.GDBusServerModule
  class codegen.GIRWriter
 
class vala.AttributeCache
  class codegen.CCodeAttribute
 
class codegen.CCodeCompiler
 
class codegen.TypeRegisterFunction
  class codegen.ClassRegisterFunction
  class codegen.EnumRegisterFunction
  class codegen.InterfaceRegisterFunction
  class codegen.StructRegisterFunction
 
class vala.CodeNode
  class vala.Expression
    class vala.AddressofExpression
    class vala.ArrayCreationExpression
    class vala.Assignment
    class vala.BaseAccess
    class vala.BinaryExpression
    class vala.Literal
      class vala.BooleanLiteral
      class vala.CharacterLiteral
      class vala.IntegerLiteral
      class vala.NullLiteral
      class vala.RealLiteral
      class vala.RegexLiteral
      class vala.StringLiteral
    class vala.CastExpression
    class vala.ConditionalExpression
    class vala.ElementAccess
    class vala.InitializerList
    class vala.LambdaExpression
    class vala.MemberAccess
    class vala.MethodCall
    class vala.NamedArgument
    class vala.ObjectCreationExpression
    class vala.PointerIndirection
    class vala.ReferenceTransferExpression
    class vala.SizeofExpression
    class vala.SliceExpression
    class vala.Template
    class vala.Tuple
    class vala.TypeCheck
    class vala.TypeofExpression
    class vala.UnaryExpression
  class vala.DataType
    class codegen.CType
    class vala.ReferenceType
      class vala.ArrayType
      class vala.ClassType
      class vala.ErrorType
      class vala.InterfaceType
      class vala.NullType
      class vala.ObjectType
    class vala.ValueType
      class vala.BooleanType
      class vala.EnumValueType
      class vala.FloatingType
      class vala.IntegerType
      class vala.StructValueType
    class vala.DelegateType
    class vala.FieldPrototype
    class vala.GenericType
    class vala.InvalidType
    class vala.MethodType
    class vala.PointerType
    class vala.PostfixExpression
    class vala.SignalType
    class vala.UnresolvedType
    class vala.VoidType
  class vala.Symbol
    class vala.Variable
      class vala.Field : interface vala.Lockable
        class vala.ArrayLengthField
      class vala.LocalVariable
      class vala.Parameter
    class vala.Block : interface vala.Statement
      class vala.ForeachStatement
      class vala.SwitchSection
    class vala.Subroutine
      class vala.Method
        class vala.ArrayMoveMethod
        class vala.ArrayResizeMethod
        class vala.CreationMethod
      class vala.Constructor
      class vala.Destructor
      class vala.DynamicMethod
      class vala.PropertyAccessor
    class vala.TypeSymbol
      class vala.ObjectTypeSymbol
        class vala.Class
        class vala.Interface
      class vala.Delegate
      class vala.Enum
      class vala.ErrorCode
      class vala.ErrorDomain
      class vala.Struct
    class vala.Constant : interface vala.Lockable
      class vala.EnumValue
    class vala.Property : interface vala.Lockable
      class vala.DynamicProperty
    class vala.Signal : interface vala.Lockable
      class vala.DynamicSignal
    class vala.Namespace
    class vala.TypeParameter
    class vala.UnresolvedSymbol
  class vala.Attribute
  class vala.BreakStatement : interface vala.Statement
  class vala.CatchClause
  class vala.ContinueStatement : interface vala.Statement
  class vala.DeclarationStatement : interface vala.Statement
  class vala.DeleteStatement : interface vala.Statement
  class vala.DoStatement : interface vala.Statement
  class vala.EmptyStatement : interface vala.Statement
  class vala.ExpressionStatement : interface vala.Statement
  class vala.ForStatement : interface vala.Statement
  class vala.IfStatement : interface vala.Statement
  class vala.LockStatement : interface vala.Statement
  class vala.Loop : interface vala.Statement
  class vala.ReturnStatement : interface vala.Statement
  class vala.MemberInitializer
  class vala.StatementList : interface vala.Statement
  class vala.SwitchLabel
  class vala.SwitchStatement : interface vala.Statement
  class vala.ThrowStatement : interface vala.Statement
  class vala.TryStatement : interface vala.Statement
  class vala.UnlockStatement : interface vala.Statement
  class vala.UsingDirective
  class vala.WhileStatement : interface vala.Statement
  class vala.YieldStatement : interface vala.Statement
  interface vala.Statement
 
class vala.BasicBlock
 
class vala.CodeContext
 
class vala.Comment
  class vala.GirComment
 
class vala.Genie.Scanner
 
class vala.Scanner
 
class vala.Scope
 
class vala.SourceFile
 
class vala.SourceReference
 
class vala.TargetValue
 
class Object
  class vala.MarkupReader
  class vala.Report
 
class vala.PhiFunction
 
interface vala.Lockable
 
class ccode.CCodeNode
  class ccode.CCodeExpression
    class ccode.CCodeAssignment
    class ccode.CCodeBinaryExpression
    class ccode.CCodeCastExpression
    class ccode.CCodeCommaExpression
    class ccode.CCodeConditionalExpression
    class ccode.CCodeConstant
    class ccode.CCodeElementAccess
    class ccode.CCodeFunctionCall
    class ccode.CCodeIdentifier
    class ccode.CCodeInitializerList
    class ccode.CCodeInvalidExpression
    class ccode.CCodeMemberAccess
    class ccode.CCodeParenthesizedExpression
    class ccode.CCodeUnaryExpression
  class ccode.CCodeStatement
    class ccode.CCodeBlock
      class ccode.CCodeSwitchStatement
    class ccode.CCodeBreakStatement
    class ccode.CCodeCaseStatement
    class ccode.CCodeContinueStatement
    class ccode.CCodeDeclaration
    class ccode.CCodeDoStatement
    class ccode.CCodeEmptyStatement
    class ccode.CCodeExpressionStatement
    class ccode.CCodeForStatement
    class ccode.CCodeGotoStatement
    class ccode.CCodeIfStatement
    class ccode.CCodeLabel
    class ccode.CCodeReturnStatement
    class ccode.CCodeWhileStatement
  class ccode.CCodeComment
  class ccode.CCodeDeclarator
    class ccode.CCodeFunctionDeclarator
    class ccode.CCodeVariableDeclarator
  class ccode.CCodeEnum
  class ccode.CCodeEnumValue
  class ccode.CCodeFragment
    class ccode.CCodeOnceSection
  class ccode.CCodeFunction
  class ccode.CCodeIncludeDirective
  class ccode.CCodeLineDirective
  class ccode.CCodeMacroReplacement
  class ccode.CCodeNewline
  class ccode.CCodeParameter
  class ccode.CCodeStruct
  class ccode.CCodeTypeDefinition
 
class ccode.CCodeFile
 
enum ccode.CCodeModifiers
 
class ccode.CCodeWriter
 
class compiler.Compiler

Over!

[Vala] D-Bus 客户端例程:方法调用返回多个值

Vala D-Bus Client Examples 中描述了如何通过定义 D-Bus 接口至 Vala 的 Interface 的映射,并创建一个实现了此本地 Interface 的 Proxy,进行方法调用、属性访问与信号侦听。

但在最近的开发中遇到了 D-Bus 接口中方法返回两个或多个值的情况,这样的情况又如何定义接口方法?看下面的例子:

例如接口 org.freedesktop.Telepathy.Connection.FUTURE 存在一个方法 EnsureSidecar,其原型如下:

EnsureSidecar (s: Main_Interface) → o: Path, a{sv}: Properties

正确定义 1:

namespace Hev {
 
    [DBus (name = "org.freedesktop.Telepathy.Connection.FUTURE")]
    public interface Future : GLib.Object {
        public abstract void ensure_sidecar (string iface, out ObjectPath path,
                out HashTable<string,Variant> props) throws IOError;
    }
}

正确定义2:

namespace Hev {
 
    [DBus (name = "org.freedesktop.Telepathy.Connection.FUTURE")]
    public interface Future : GLib.Object {
        public abstract HashTable<string,Variant> ensure_sidecar (string iface,
                out ObjectPath path) throws IOError;
    }
}

错误定义:

namespace Hev {
 
    [DBus (name = "org.freedesktop.Telepathy.Connection.FUTURE")]
    public interface Future : GLib.Object {
        public abstract ObjectPath ensure_sidecar (string iface,
                out HashTable<string,Variant> props) throws IOError;
    }
}

从上面的例子中可以看出优先级是:out 参数 > 返回值,为了更直观,建议使用正确定义1的方式。

Over!

组播技术中IPv4地址到MAC地址的映射

以太网组播MAC地址

以太网传输单播IP报文的时候,目的MAC地址使用的是接收者的MAC地址。但是在传输组播数据包时,其目的地不再是一个具体的接收者,而是一个成员不确定的组,所以要使用组播MAC地址。

IPv4组播MAC地址
IANA规定,IPv4组播MAC地址的高24位为0x01005E,第25位为0,低23位为IPv4组播地址的低23位。IPv4组播地址与MAC地址的映射关系如图1-6所示。

图1-6 IPv4组播地址与MAC地址的映射关系

由于IPv4组播地址的高4位是1110,代表组播标识,而低28位中只有23位被映射到IPv4组播MAC地址,这样IPv4组播地址中就有5位信息丢失。于是,就有32个IPv4组播地址映射到了同一个IPv4组播MAC地址上,因此在二层处理过程中,设备可能要接收一些本IPv4组播组以外的组播数据,而这些多余的组播数据就需要设备的上层进行过滤了。

Over!

From: http://0bill0.blog.51cto.com/195306/300481

Telepathy 即时通信框架

Telepathy 是一个灵活的、模块化的通信框架,通过可插拨的协议后端能实现实时通信。Telepathy 作为一个通信服务可同时被多个应用程序(客户端)访问。

这允许任何客户端访问 Presence 信息,请求一个 Channel (可由其它客户端处理)及基于 Tube 的客户端协作处理。

Telepathy 通过统一的 D-Bus API 提供了很多流行的协议后端支持,包括:Jabber/XMPP/Google Talk/Jingle, link-local XMPP, SIP, MSN, Yahoo/AIM and IRC。

另外,它还提供了方便的库接口使得使用 GLib, Qt4 以及 Python 可以简单的从应用程序访问这些 API。

Telepathy 为每个协议导出了有效的实时通信能力,如 Presence,联系人列表,文本聊天,音频、视频通信,文件传输及 Tubes。

Telepathy 是模块化的,每个后端和客户端都运行在一个独立的进程上,尽最大的保证安全和适应性。

Over!