系统态和用户态
系统态(也称为管态或核心态),操作系统在系统态运行
1) 特权指令——在系统态时运行的指令
对内存空间的访问范围基本不受限制,不仅能访问用户存储空间,也能访问系统存储空间,
一般应用程序所使用的都是非特权指令,它只能完成一般性的操作和任务,不能对系统中的硬件和软件直接进行访问,其对内存的访问范围也局限于用户空间。
系统调用的类型
对于一般通用的 OS 而言,可将其所提供的系统调用分为:进程控制、文件操纵、通信管理和系统维护等几大类。
系统调用的实现
系统调用的实现与一般过程调用的实现相比,两者间有很大差异。对于系统调用,控制是由原来的用户态转换为系统态,这是借助于中断和陷入机制来完成的,在该机制中包括中断和陷入硬件机构及中断与陷入处理程序两部分。当应用程序使用 OS 的系统调用时,产生一条相应的指令,CPU 在执行这条指令时发生中断,并将有关信号送给中断和陷入硬件机构,该机构收到信号后,启动相关的中断与陷入处理程序进行处理,实现该系统调用所需要的功能。
socket()函数系统调用过程
在sys_socketcall()函数中可以看到,socket系统调用最终调用的是sys_socket()函数
sys_socket()函数声明如下:
asmlinkage long sys_socket(int, int, int);
同样的,sys_socket()函数实现为:
sys_socket()
参数kern:表示由应用程序还是内核创建该套接口,一般为0(表示应用程序),或者1(表示内核)。
sock_create()函数
这个函数是对__socket_create函数的封装,直接调用__sock_create()函数。
int sock_create(int family, int type, int protocol, struct socket **res) { return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0); }
__sock_create()函数
创建socket及inode
int __sock_create(struct net *net, int family, int type, int protocol, struct socket **res, int kern) { int err; struct socket *sock; const struct net_proto_family *pf; /* * Check protocol is in range */ /*family和type字段范围检查*/ if (family < 0 || family >= NPROTO) return -EAFNOSUPPORT; if (type < 0 || type >= SOCK_MAX) return -EINVAL; /* Compatibility. This uglymoron is moved from INET layer to here to avoid deadlock in module load. */ /*兼容性考虑,IPv4协议族的SOCK_PACKET已经废弃,当family ==F_INET && type == SOCK_PACKET时, 强制把family改为PF_PACKET。*/ if (family == PF_INET && type == SOCK_PACKET) { static int warned; if (!warned) { warned = 1; pr_info("%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->comm); } family = PF_PACKET; } /*安全模块对套接口的创建做检查,安全模块不是网络中必需的组成部门,不做讨论。*/ // 检查权限,并考虑协议集、类型、协议,以及 socket 是在内核中创建还是在用户空间中创建 // 可以参考:https://www.ibm.com/developerworks/cn/linux/l-selinux/ err = security_socket_create(family, type, protocol, kern); if (err) return err; /* * Allocate the socket and allow the family to set things up. if * the protocol is 0, the family is instructed to select an appropriate * default. */ /*调用sock_alloc()在sock_inode_cache缓存中分配与套接口关联的i结点和套接口,同时 初始化i结点和套接口,失败则直接返回错误码。*/ sock = sock_alloc(); if (!sock) { net_warn_ratelimited("socket: no more sockets\n"); return -ENFILE; /* Not exactly a match, but its the closest posix thing */ } sock->type = type; /*如果协议族支持内核模块动态加载,但在创建此协议族类型的套接字时,内核模块并未被加载,则调用 request_module()进行内核模块的动态加载。*/ #ifdef CONFIG_MODULES /* Attempt to load a protocol module if the find failed. * * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user * requested real, full-featured networking support upon configuration. * Otherwise module support will break! */ if (rcu_access_pointer(net_families[family]) == NULL) request_module("net-pf-%d", family); #endif rcu_read_lock(); /*获取对应协议的net_proto_family指针*/ pf = rcu_dereference(net_families[family]); err = -EAFNOSUPPORT; if (!pf) goto out_release; /* * We will call the ->create function, that possibly is in a loadable * module, so we have to bump that loadable module refcnt first. */ /*如果对应协议族模块是动态加载到内核中去的,则对此内核模块的应用计数+1,以防 在创建过程中,该模块被卸载,造成严重的后果。*/ if (!try_module_get(pf->owner)) goto out_release; /* Now protected by module ref count */ rcu_read_unlock(); /*在IPv4协议族中调用inet_create()对已创建的socket继续进行初始化,同时创建网络层socket。*/ err = pf->create(net, sock, protocol, kern); if (err < 0) goto out_module_put; /* * Now to bump the refcnt of the [loadable] module that owns this * socket at sock_release time we decrement its refcnt. */ /*如果proto_ops结构实例所在模块以内核模块方式动态加载进内核, 则增加该模块的引用计数,在sock_release时,减小该计数。*/ if (!try_module_get(sock->ops->owner)) goto out_module_busy; /* * Now that we‘re done with the ->create function, the [loadable] * module can have its refcnt decremented */ /*调用完inet_create函数后,对此模块的引用计数减一。*/ module_put(pf->owner); /*安全模块对创建后的socket做安全检查,不做讨论。*/ err = security_socket_post_create(sock, family, type, protocol, kern); if (err) goto out_sock_release; *res = sock; return 0; out_module_busy: err = -EAFNOSUPPORT; out_module_put: sock->ops = NULL; module_put(pf->owner); out_sock_release: sock_release(sock); return err; out_release: rcu_read_unlock(); goto out_sock_release; }
sock_alloc()函数
sock_alloc()函数,创建i结点和socket,i结点和socket是绑定在一起的,放在结构体socket_alloc中,并且进行相关初始化。
static struct socket *sock_alloc(void) { struct inode *inode; struct socket *sock; /*创建i借点和socket*/ inode = new_inode_pseudo(sock_mnt->mnt_sb); if (!inode) return NULL; /*返回创建的socket指针*/ sock = SOCKET_I(inode); kmemcheck_annotate_bitfield(sock, type); /*inode相关初始化*/ inode->i_ino = get_next_ino(); inode->i_mode = S_IFSOCK | S_IRWXUGO; inode->i_uid = current_fsuid();//用户id inode->i_gid = current_fsgid();//组id inode->i_op = &sockfs_inode_ops;//inode的操作函数指针指向sockfs_inode_ops this_cpu_add(sockets_in_use, 1); return sock; }
原文:https://www.cnblogs.com/xiehuichina/p/12069380.html