asmlinkage long sys_socket(int, int, int);//声明,所在文件include/linux/syscalls.h
函数的声明中,比较有趣的点在asmlinkage这块,追踪这块:
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
此时我们发现asmlinkage是一个宏定义,继续追踪:
#define CPP_ASMLINKAGE extern "C"
对于extern "C"相比大家已经很熟悉了,意思是long sys_socket(int, int, int)按c语言进行编译
对__attribute__百度有:它可以设置函数属性、变量属性和类型属性等。可以通过它们向编译器提供更多数据,帮助编译器执行优化等。
__attribute__((regparm(0))):告诉gcc编译器该函数不需要通过任何寄存器来传递参数,参数只是通过堆栈来传递。
(http://www.chinaitlab.com/linux/kernel/883881.html)
该声明已经解析完成
SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)//该函数的定义
{
int retval;
struct socket *sock;
int flags;
/* Check the SOCK_* constants for consistency. */
BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC);
BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK);
BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK);
BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK);
flags = type & ~SOCK_TYPE_MASK;
if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
return -EINVAL;
type &= SOCK_TYPE_MASK;
if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
retval = sock_create(family, type, protocol, &sock);
if (retval < 0)
goto out;
retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
if (retval < 0)
goto out_release;
out:
/* It may be already another descriptor 8) Not kernel problem. */
return retval;
out_release:
sock_release(sock);
return retval;
}
1.追踪 SYSCALL_DEFINE3
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
发现SYSCALL_DEFINE3是一个宏定义,首先先对宏定义进行说明下:
1. ...:省略号代表可变的部分,下面用__VA_AEGS__ 代表省略的变长部分;
2. ##:分隔连接方式,它的作用是先分隔,然后进行强制连接,例如:
#define VAR(type, name) type name##_##type
VAR(int, var1);
展开之后就是:
int var1_int;
那么SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)展开之后:
SYSCALL_DEFINEx(3, _socket, __VA_ARGS__)
摘自:http://blog.csdn.net/hazir/article/details/11835025
继续查看SYSCALL_DEFINEx
#ifdef CONFIG_FTRACE_SYSCALLS
#define SYSCALL_DEFINEx(x, sname, ...) \
static const char *types_##sname[] = {\
__SC_STR_TDECL##x(__VA_ARGS__)\
}; \
static const char *args_##sname[] = {\
__SC_STR_ADECL##x(__VA_ARGS__)\
}; \
SYSCALL_METADATA(sname, x);\
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#else
#define SYSCALL_DEFINEx(x, sname, ...) \
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
可以看到,不论是何种形式的宏定义,最终都会进入__SYSCALL_DEFINEx中,对于这块按照上面进行展开:
__SYSCALL_DEFINEx(3, _socket, __VA_ARGS__)
继续追踪:
#define __SYSCALL_DEFINEx(3, name, ...) \
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))
展开:asmlinkage long sys_socket(__SC_DECL##3(int, family, int, type, int, protocol))
对__SC_DECL:
#define __SC_DECL1(t1, a1) t1 a1
#define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__)
#define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__)
#define __SC_DECL4(t4, a4, ...) t4 a4, __SC_DECL3(__VA_ARGS__)
#define __SC_DECL5(t5, a5, ...) t5 a5, __SC_DECL4(__VA_ARGS__)
#define __SC_DECL6(t6, a6, ...) t6 a6, __SC_DECL5(__VA_ARGS__)
__SC_DECL##3(int, family, int, type, int, protocol)
==>__SC_DECL3(int, family, int, type, int, protocol)
==>int family,__SC_DECL2(int, type, int, protocol)
==>int family,int type,__SC_DECL1( int, protocol)
==>int family,int type,int protocol
即得出:asmlinkage long sys_socket(int family,int type,int protocol)
为什么要这么麻烦引出系统调用,我只能说那帮大牛纯粹有病,当然事实上肯定不是了,原因:http://blog.csdn.net/hazir/article/details/11835025
有看似合理的解释。其实现在一直有个疑惑,为什么这帮大牛们特别喜欢用宏定义?
2.内部函数及参数
首先感觉这块没有太多要注解的东西,先说明下三个参数吧:
family:待创建接口的协议族,如:PF_INET,PF_UNIX;
type:待创建套接口的类型:如SOKC_STREAM,SOCK_DGRAM,SOCK_RAW;
protocol:传输层协议,IPPPOTO_TCP、IPPPOTO_UDP;
其次我们注意到,函数里面最重要是调用了两个函数:
1.sock_create:根据family, type, protocol创建并初始化一个套接口
2.sock_map_fd:给创建的套接口分配一个文件描述符并绑定
注解:整块,个人觉得最用该留意的细节一个是为何要用到如此之多宏定义来引出系统调用,即asmlinkage;其对flag的判断的位操作。