彻底的系统调用---open函数

Linux 系统调用之open(一) Linux下一切设备均视为文件,本文来简单分析下系统调用里面是如何打开文件的。本文仅以下面简单代码为例,看Linux内核如何完成open的系统调用的(参考内核版本:4.14.13,x86_64)。为了简单起见,本文中暂时忽略并发性访问的同步问题以及错误处理(一般情况下,上述事例中的操作都会成功,除非有权限问题,所以我们先不考虑函数调用失败的情况)。#include <stdio.h> ... 阅读详情


先写个简单的test.c
#include <linux/module.h>
#include <linux/init.h>

#include <linux/fs.h>
#include <linux/cdev.h>

#include <linux/errno.h>

struct cdev test_cdev;
dev_t devno;
unsigned int major = 0;
unsigned int minor = 0;

int test_open (struct inode *nod, struct file *filp)
{
    printk("<kernel> %s\n", __FUNCTION__);            
    return 0;
}

struct file_operations test_ops = {
    .open = test_open,
};

int init_test(void)
{
    int err = 0;

    err = alloc_chrdev_region(&devno, 0, 1, "alloc register");
    if(err){
        printk("<kernel> cdev_add failed\n");            
        err = -EBUSY;
        goto fail;
    }

    major = MAJOR(devno);
    minor = MINOR(devno);
    printk("major is [%d], minor is [%d]\n", major, minor);

    cdev_init(&test_cdev, &test_ops);

    err = cdev_add(&test_cdev, devno, 1);    
    if(err){
        printk("<kernel> cdev_add failed\n");            
        err = -ENODEV;
        goto fail1;
    }

    printk("<kernel>init \n");        
    return 0;

fail:
    return err;
fail1:
    unregister_chrdev_region(devno, 1);        
    return err;
}

void exit_test(void)
{
    cdev_del(&test_cdev);
    unregister_chrdev_region(devno, 1);        
    printk("bye\n");        
}

module_init(init_test);
module_exit(exit_test);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("Jesse");
MODULE_DESCRIPTION("this is a test module");
MODULE_VERSION("v0.1");
复制代码
  
仅一个简单的open,应该不会有更简单的字符设备驱动了。
app 层还应该有这么个东西。
fd = open("/dev/test", O_RDWR);
好了,上面下面都有了。那,中间是怎么个回事?
大致的过程:
  
fd = open("/dev/test", O_RDWR);
sys_open
test_open
    
这个sys_open()可不是一个简单的函数,它包括了文件路径查找,文件权限判断等各种复杂BT的步骤。况且,不知何时起,内核里的sys_open已不是曾经的那个光明磊落的sys_open,tag不到,即便find到,也是一些bt的形式,早已面目全非。

     
-- fs/open.c --
 
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)
{
    long ret; 

    if (force_o_largefile())
        flags |= O_LARGEFILE;

    ret = do_sys_open(AT_FDCWD, filename, flags, mode);        //==>bb

    /* avoid REGPARM breakage on x86: */
    asmlinkage_protect(3, ret, filename, flags, mode);
    return ret; 
}
复制代码
有人问了,这个SYSCALL_DEFINE3是个什么东西,“你最好不要追究这样的问题”。
内核里的各种宏定义,不是一般的有才。简单的gcc -E一下 简单的瞧瞧。
    
#define __SYSCALL_DEFINEx(x, name, ...)                 \
    asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__));       \
    static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__));   \
    asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__))        \
    {                               \
        __SC_TEST##x(__VA_ARGS__);              \
        return (long) SYSC##name(__SC_CAST##x(__VA_ARGS__));    \
    }                               \
    SYSCALL_ALIAS(sys##name, SyS##name);                \
    static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__))


#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__)

#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)

int main(void)
{
    SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode);

}
复制代码
展开真面目:
int main(void)
{

    static const char *types__open[] = { __SC_STR_TDECL3(const char __user *, filename, int, flags, int, mode) };
    static const char *args__open[] = { __SC_STR_ADECL3(const char __user *, filename, int, flags, int, mode) }; 
    SYSCALL_METADATA(_open, 3); 
    asmlinkage long sys_open(__SC_DECL3(const char __user *, filename, int, flags, int, mode)); 
    static inline long SYSC_open(__SC_DECL3(const char __user *, filename, int, flags, int, mode)); 
    asmlinkage long SyS_open(__SC_LONG3(const char __user *, filename, int, flags, int, mode)) 
    {
         __SC_TEST3(const char __user *, filename, int, flags, int, mode); 
         return (long) SYSC_open(__SC_CAST3(const char __user *, filename, int, flags, int, mode)); 
    }
    SYSCALL_ALIAS(sys_open, SyS_open); 
    static inline long SYSC_open(__SC_DECL3(const char __user *, filename, int, flags, int, mode));

}
复制代码
一些宏还未展开,点到为止,见好就收吧。
       
我们继续往下看。
     
bb:
long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
{
    char *tmp = getname(filename);    //filename复制到了内核空间,即 *tmp ==>cc
    int   fd  = PTR_ERR(tmp);        //return (long) ptr;

    if (!IS_ERR(tmp)) {
        fd = get_unused_fd_flags(flags);    //得到一个有效的fd ==>dd
        if (fd >= 0) {
            struct file *f = do_filp_open(dfd, tmp, flags, mode, 0);    // ==>ee
            if (IS_ERR(f)) {
                put_unused_fd(fd);
                fd = PTR_ERR(f);
            } else {
                fsnotify_open(f->f_path.dentry);    //==>ff
                fd_install(fd, f);    //将 fd 与file结构关联,以便 read write 等系统调用使用 ==>gg
            }    
        }    
        putname(tmp);    //分配完毕,释放掉暂时保存filename的内核空间:kmem_cache_free
    }    
    return fd;
}
复制代码
         
cc:
#define __getname_gfp(gfp)  kmem_cache_alloc(names_cachep, (gfp))
#define __getname()     __getname_gfp(GFP_KERNEL)

char * getname(const char __user * filename)
{
    char *tmp, *result;

    result = ERR_PTR(-ENOMEM);
    tmp = __getname();        // kmem_cache_alloc: 内存分配出一块空间
    if (tmp)  {
        int retval = do_getname(filename, tmp);    //copy filenames to the kernel data space(*tmp) before using them

        result = tmp;
        if (retval < 0) {
            __putname(tmp);
            result = ERR_PTR(retval);
        }
    }
    audit_getname(result);
    return result;
}
复制代码
dd:
#define get_unused_fd_flags(flags) alloc_fd(0, (flags))

-- fs/file.c --

/*
 * allocate a file descriptor, mark it busy.
 */
int alloc_fd(unsigned start, unsigned flags)
{   
    struct files_struct *files = current->files;
    unsigned int fd;
    int error;
    struct fdtable *fdt;

    spin_lock(&files->file_lock);

repeat:
    fdt = files_fdtable(files);
    fd = start;
    if (fd < files->next_fd)
        fd = files->next_fd;

    if (fd < fdt->max_fds)
        fd = find_next_zero_bit(fdt->open_fds->fds_bits,
                                fdt->max_fds, 
                                fd);    //这个很熟悉的函数==>ddD

    error = expand_files(files, fd);
    if (error < 0)
        goto out;

    /*
     * If we needed to expand the fs array we
     * might have blocked - try again.
     */
    if (error)
        goto repeat;

    if (start <= files->next_fd)
        files->next_fd = fd + 1;

    FD_SET(fd, fdt->open_fds);
    if (flags & O_CLOEXEC)
        FD_SET(fd, fdt->close_on_exec);
    else
        FD_CLR(fd, fdt->close_on_exec);

    error = fd;

#if 1
    /* Sanity check */
    if (rcu_dereference(fdt->fd[fd]) != NULL) {
        printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd);
        rcu_assign_pointer(fdt->fd[fd], NULL);
    }
#endif

out:
    spin_unlock(&files->file_lock);
    return error;
}
复制代码
ddD:
  一个出镜率很高的函数,常用于各种什么符的的分配。当然了,这些符都是按顺序分配di,用类似数组的形式,数组里的0表示未分配,然后遍历去找这些0。
unsigned long find_next_zero_bit(const unsigned long *addr, 
                              unsigned long size,
                                 unsigned long offset)
{
    const unsigned long *p = addr + BITOP_WORD(offset);    //p = addr
    unsigned long result = offset & ~(BITS_PER_LONG-1);    //result = 0
    unsigned long tmp;

    if (offset >= size)
        return size;

    size   -= result;        
    offset %= BITS_PER_LONG; 
    if (offset) {
        tmp = *(p++);
        tmp |= ~0UL >> (BITS_PER_LONG - offset);
        if (size < BITS_PER_LONG)
            goto found_first;
        if (~tmp)
            goto found_middle;
        size -= BITS_PER_LONG;
        result += BITS_PER_LONG;
    }

    while (size & ~(BITS_PER_LONG-1)) {

        if (~(tmp = *(p++)))
            goto found_middle;
        result += BITS_PER_LONG;
        size -= BITS_PER_LONG;
    }

    if (!size)
        return result;

    tmp = *p;

found_first:
    tmp |= ~0UL << size;
    if (tmp == ~0UL)    /* Are any bits zero? */
        return result + size;   /* Nope. */

found_middle:
    return result + ffz(tmp);
}
复制代码
           
下面是理解的重点,也是一调到底的精髓。重点在于struct file的分配。
         
ee:
/*
 * Note that the low bits of the passed in "open_flag"
 * are not the same as in the local variable "flag". See
 * open_to_namei_flags() for more details.
 */
struct file *do_filp_open(int dfd, const char *pathname,        
                          int open_flag, int mode, int acc_mode)
{
    struct file *filp;
    struct nameidata nd;
    int error;
    struct path path;
    struct dentry *dir;
    int count = 0;
    int will_write;
    int flag = open_to_namei_flags(open_flag);

    /* 设置open的 mode */
    if (!acc_mode)
        acc_mode = MAY_OPEN | ACC_MODE(flag);
                
    /* O_TRUNC implies we need access checks for write permissions */
    if (flag & O_TRUNC)
        acc_mode |= MAY_WRITE; 
            
    /* Allow the LSM permission hook to distinguish append 
       access from general write access. */
    if (flag & O_APPEND)
        acc_mode |= MAY_APPEND;

    /*
     * The simplest case - just a plain lookup.
     */
    if (!(flag & O_CREAT)) {
        error = path_lookup_open(dfd, pathname, lookup_flags(flag),
                                 &nd, flag);    
        if (error)
            return ERR_PTR(error);
        goto ok;
    }

    ...
    ...

ok:

    /*
     * Consider:
     * 1. may_open() truncates a file
     * 2. a rw->ro mount transition occurs
     * 3. nameidata_to_filp() fails due to
     *    the ro mount.
     * That would be inconsistent, and should
     * be avoided. Taking this mnt write here
     * ensures that (2) can not occur.
     */
    will_write = open_will_write_to_fs(flag, nd.path.dentry->d_inode);
    if (will_write) {
        error = mnt_want_write(nd.path.mnt);
        if (error)
            goto exit;
    }
    error = may_open(&nd.path, acc_mode, flag);    //**
    if (error) {
        if (will_write)
            mnt_drop_write(nd.path.mnt);
        goto exit;
    }
    filp = nameidata_to_filp(&nd, open_flag);    //分配struct file,得到filp
    if (IS_ERR(filp))
        ima_counts_put(&nd.path,
                       acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC));
    /*
     * It is now safe to drop the mnt write
     * because the filp has had a write taken
     * on its behalf.
     */
    if (will_write)
        mnt_drop_write(nd.path.mnt);
    if (nd.root.mnt)
        path_put(&nd.root);
    return filp;

    ...
    ...

}
复制代码
            
struct file *nameidata_to_filp(struct nameidata *nd, int flags)
{
    const struct cred *cred = current_cred();
    struct file *filp;

    /* Pick up the filp from the open intent */
    filp = nd->intent.open.file;
    /* Has the filesystem initialised the file for us? */
    if (filp->f_path.dentry == NULL)
        filp = __dentry_open(nd->path.dentry, nd->path.mnt, flags, filp,
                     NULL, cred);  //!!!
    else 
        path_put(&nd->path);
    return filp;
}
复制代码
           
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
                    int flags, struct file *f,
                    int (*open)(struct inode *, struct file *),
                    const struct cred *cred)
{
    struct inode *inode;
    int error;

    f->f_flags = flags;
    f->f_mode = (__force fmode_t)((flags+1) & O_ACCMODE) | FMODE_LSEEK |
                FMODE_PREAD | FMODE_PWRITE;
    inode = dentry->d_inode;
    if (f->f_mode & FMODE_WRITE) {
        error = __get_file_write_access(inode, mnt);
        if (error)
            goto cleanup_file;
        if (!special_file(inode->i_mode))
            file_take_write(f);
    }

    f->f_mapping = inode->i_mapping;
    f->f_path.dentry = dentry;
    f->f_path.mnt = mnt;
    f->f_pos = 0;
    f->f_op = fops_get(inode->i_fop);  //!!! !!!
    file_move(f, &inode->i_sb->s_files);

    error = security_dentry_open(f, cred);
    if (error)
        goto cleanup_all;

    if (!open && f->f_op)  //f->f_op若有,则执行open
        open = f->f_op->open;  
    if (open) {
        error = open(inode, f);
        if (error)
            goto cleanup_all;
    }

    f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

    file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
复制代码
          
说下六个感叹号的地方。记得我们在注册字符设备的时候是否有个cdev_init ? 她的体内是不是有个 cdev->ops = fops ?
inode里是不是有个i_cdev ?
这里,file的f_op是不是被赋了inode的i_fop ?
打开struct file, struct inode的定义处,多瞧上两眼。这里就不贴了。
         
就这样,fd = open("/dev/test", O_RDWR) 最终还是调到了test_open 。
             
最后就是个首尾函数,将得到的fd和struct file关联起来。
         
gg:
void fd_install(unsigned int fd, struct file *file)
{   
    struct files_struct *files = current->files;
    struct fdtable *fdt;

    spin_lock(&files->file_lock);

    fdt = files_fdtable(files);
    BUG_ON(fdt->fd[fd] != NULL);
    rcu_assign_pointer(fdt->fd[fd], file);

    spin_unlock(&files->file_lock);
}
复制代码
           
do_sys_open 的结尾 return fd;  返回给 app。
  fd = open("/dev/test", O_RDWR) 
          
  你懂的。




Linux 系统调用之open(三) 前面我们以及其简单的例子分析了linux的open系统调用过程。下面换一个例子,假如我们有个字符驱动:my_kmem.ko。使用如下脚本将其加载入内核空间:#!/bin/sh module="my_kmem" device="my_chr_dev" mod="664" insmod $module.ko || exit 1 rm -f /dev/${device}0 major=`awk ... 阅读详情

相关推荐

Fortran环境配置:VS2022+Intel oneAPI安装全流程指南

Fortran环境配置:VS2022+Intel oneAPI安装全流程指南

shuyisuisuinian的博客 2万+

linux内核sys_open源代码分析

打开一个文件,是通过内核提供的系统调用sys_open来实现的,在用户空间的open函数会被编译器编译成为int 80的汇编代码,进入内核空间执行打开操作,我们来顺着内核的代码来看一下具体的实现过程。 sys_open函数定义在fs/open.c文件,定义如下 asmlinkage long sys_open(const char __user *filename, int flags, in

love coding 1万+

【机器学习】图神经网络(NRI)模型原理和运动轨迹预测代码实现

NRI模型利用VAE和GNN从观测数据中学习系统动态和交互图,展现出在无监督学习、图结构建模、多步预测和连续松弛方面的强大能力。未来工作可探索动态图结构学习、应用于更复杂系统、提高模型泛化能力和计算效率,以及与其他模型的结合。NRI作为新兴的图神经网络方法,在理解和预测相互作用系统方面潜力巨大,有望在各领域发挥重要作用。

MUKAMO的博客 2777

Linux-0.12内核打开文件过程--sys_open源码分析

上图展示了进程打开文件使用的内核数据结构,所以要打开文件,就要构造上图中的关系。 int sys_open(const char *filename,int flag,int mode) { struct m_inode *inode; struct file *f; int i,fd; mode&=0777&~current->umask; //在filp数组中寻找“空闲位置”

GetnextWindow的专栏 3000

手把手教你搭建幽冥传奇手游:从环境配置到常见Bug修复(附完整避坑指南)

本文详细指导如何从零搭建幽冥传奇手游,涵盖服务器选型、数据库部署、双区架构配置等关键步骤,并提供通天塔闪退、技能显示异常等常见Bug的修复方案。附完整避坑指南,帮助开发者高效解决90%的典型问题,确保游戏稳定运行。

weixin_29232121的博客 241

线性回归做糖尿病分析(diabetes数据集),并分析单个特征值与病情的关系

1.diabetes数据集 共442个样本,每个样本有十个特征,分别是 [‘age’, ‘sex’, ‘bmi’, ‘bp’, ‘s1’, ‘s2’, ‘s3’, ‘s4’, ‘s5’, ‘s6’],对应年龄、性别、体质指数、平均血压、S1~S6一年后疾病级数指标。 Targets为一年后患疾病的定量指标,值在25到346之间。 ...

t18438605018的博客 1万+

详解sys_open

内核源码:linux-2.6.38.8.tar.bz2 目标平台:ARM体系结构   在Linux系统中,打开或创建文件大概有以下三种形式:   系统调用sys_creat仅仅是对sys_open函数的简单封装。 只有当参数filename为相对路径时,参数dfd才有意义,表示文件filename存在于文件描述符dfd所表示的目录之下。当dfd的值为AT_FDCWD时,则表示该文件位于

tanglinux 1万+

三相五柱式消弧线圈自动测控装置设计与实现

本文设计了一种基于STM32的三相五柱式消弧线圈自动测控装置。该装置采用信号注入法检测系统对地电容电流,通过PID自适应算法调节消弧线圈电感值,实现单相接地故障时的快速补偿。硬件系统包含信号采集、注入、控制执行等模块,软件采用Goertzel算法提取特征频率信号,结合增量式PID实现精确控制。实验结果表明,装置电容检测误差小于2%,调谐响应时间小于50ms,满足配电网对消弧线圈自动调谐的技术要求。

AI的内部世界的博客 238

文件操作——系统调用函数open函数(含文件描述符介绍)

C/C++向文件写入,先调用接口函数 ——> 系统调用函数 ——>进入OS ——> 从磁盘中读取文件,这里主要介绍系统调用函数open函数

challenglistic的博客 6897

PDN分析实战:电源完整性设计与Altium PDN Analyzer全流程指南

电源完整性(PI)是嵌入式硬件系统稳定运行的基础能力,其核心在于控制电流密度与电压降两大物理量。基于欧姆定律与热-电耦合原理,PDN分析将抽象的电源噪声问题转化为可量化、可定位的几何与电气参数优化过程。该技术显著提升系统抗干扰能力、降低复位与ADC漂移等隐性故障率,并直接支撑EMC合规性设计。典型应用场景包括电机驱动板、Wi-Fi模块、STM32/ESP32等资源受限型MCU供电网络验证。本文以Altium Designer为工具平台,结合IPC-2152标准与真实工程案例,详解从功率预算、模型构建到瓶颈定

weixin_28949937的博客 229

Windows10下安装VMware16虚拟机

由于本人系统为Windows 10 家庭中文版,无法安装Linux子系统WSL,虽然网上也有强制安装的方法,但为保险起见,还是把之前的VMware虚拟机重新进行安装,并浅浅记录一下安装过程。

沉香best的博客 863

sys_open的一些随记

先看函数原型asmlinkage long sys_open(const char __user *filename, int flags, int mode)在fs/open.c。 代码一: asmlinkage long sys_open(const char __user *filename, int flags, int mode) { long ret; if (force_o

fenglifeng1987的专栏 5117

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

系统调用的内核实现,一文讲透open函数内核真实实现。

本文接续上文,继续探寻在内核中的系统调用如何具体实现,本文以open函数为例,保证你一次性弄懂。本文采用linux3.2.1内核代码,并推荐使用Source Insight,这会让这个过程更容易。

辰子老八 3568

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

系统调用如何进入内核层次,深入glibc寻找open函数真实实现。

本文跟随上文【Linux为何一切皆文件】,继续探寻应用程序如何通过系统调用,从应用层转换到内核层,本文以open系统调用为例。我们需要查询glibc的源码包[下载处],本文使用的是最新的glibc2.30版本的源码。

辰子老八 2999

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

系统调用——open、write、read和close

一、文件描述符 每一个进程都有一个与之相关的文件描述符,它们是一些小值整数,我们可以通过这些文件描述符来访问打开的文件。 一般地,一个程序开始运行时,会自动打开3个文件描述符: 0——–标准输入———-stdin 1——–标准输出———-stdout 2——–标准错误———-二、write系统调用1.write系统调用的原型:#include <unistd.h>size_t write(

帅气的羊的博客 1万+

系统调用IO函数(例如open、write、read、remove、close)

大家好,这里是小缺,一名对嵌入式软件开发充满热情的探索者。本篇文章我将向大家介绍文件描述符,一些常见系统调用IO函数,例如open、write、read、remove、close。

BEIFEN13的博客 3144

系统调用open

exit(0)相当于「通知搬家公司来收最后一波快递」—— 进程退出时,会强制清空printf父进程退出:把自己快递柜里的「A」送上门(终端显示一个 A);子进程退出:也把自己复制来的快递柜里的「A」送上门(终端又显示一个 A)。应用程序想做特权操作(比如 open 文件),会把 “业务编号” 写在 Eax 里,触发 0x80 中断喊内核来帮忙,内核通过编号找到对应的处理函数,完成操作后把结果返回。系统调用是应用程序直接请求操作系统内核帮忙做事的接口,属于 “底层特权操作”。

m0_56799144的博客 778

Linux中open、write、read、close系统调用

个人学习整理 如有不足之处 请不吝指教 open系统调用 open函数的三个参数: (1)path是已经存在的文件的路径; (2)oflags参数:若值为 O_RDONLY ,就以只读方式打开文件;                若值为 O_WDONLY,就以只写方式打开文件;                若值为 O_RDWR,就以读写方式打开文件; (3)

MOON5555的博客 1万+

linux 系统调用 open函数使用

函数介绍 本文仅仅将open系统调用的使用简单总结一下,关于其实现原理大批的大佬分享可以自行学习。open系统调用主要用于打开或者创建一个文件,并返回文件描述符。 头文件 #include <fcntl.h> 函数名称 a. int open(const char *pathname, int flags); b. int open(const char *pathname, i...

天行健,地势坤 1679

【系统调用】常用系统调用函数:详细介绍

提供了一些常见的系统调用函数的具体介绍和代码示例,包括open、perror、close、write、read、stat、dup、fcntl等函数,涵盖了文件操作、错误处理、文件状态获取、文件描述符操作等功能。 此外,我们还介绍了其他一些与I/O和目录相关的系统调用函数,包括access、chmod、chown、truncate、link、symlink、readlink、unlink、rename、getcwd、chdir、opendir、closedir、readdir等函数,并提供了相应的代码示例。

crr411422的博客 4653

Linux的open函数的调用过程,浅析linux中open系统调用

浅析linux中open系统调用作者:吴新武,从2.6.19的linux内核开始,内核的系统调用使用函数syscall,其函数原型为:int syscall(int number, ...)其中number是系统调用号,number后面应顺序接上该系统调用的所有参数。以x86平台为例,系统调用号在内核源码中的路径是/arch/x86/include/asm/unistd_32.h头文件中定义。其中...

weixin_28818643的博客 986

系统调用和库函数

1、系统调用的本质   所有操作的本质都是要下发命名到硬件,在Linux操作系统中提供了linux内核来驱动操作硬件、为了方便用户操作相关硬件功能,所以提供了一些函数接口,用于操作Linux内核,进而由内核来操作硬件。这些接口称之为系统调用。   在Linux内核中,大多数的代码也是系统调用。在应用层调的一些函数接口,有些也是在函数接口内在调用内核中的系统调用函数。 文件io:称之为系统调用 标准io:称之为库函数 2、库函数   库函数的本质是系统调用,系统调用函数只要执行一次,就需要对Linux内核访

ZBraveHeart的博客 4000

系统调用从glibc库到内核的追踪(open函数)

http://blog.chinaunix.net/uid-29401328-id-4866849.html 前面说了glibc以及标准C库函数和系统调用,但总感觉有点隔靴挠痒,下面就来追踪一下系统调用的源码。(linux-3.3内核,glibc-2.17源码) 系统调用以open函数为例 怎么查呢? 用  man 2 open 查看open的用法,看到需要包含三个头文件sys/types.h、...

eric43的专栏 1548

系统调用open的大概执行路径

系统调用open的执行路径 代码来自Ucore教学操作系统 //用户通过open系统调用接口,执行int 0x80指令,进入内核,查找系统调用表,调用sys_open。level 1: sys_open//---level 1---static uint32_t sys_open(uint32_t arg[]) { const char *path = (const char *)arg

unclerunning的博客 3576
上一篇: sqlite3的简单使用
下一篇: 系统调用彻底理解
ADC0809608
博客等级 码龄17年 44粉丝 10原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值