精华内容
下载资源
问答
  • 安卓启动过程

    2020-01-09 10:12:07
    整个流程分为四个阶段,即引导阶段、内核启动阶段、用户态init阶段、Zygote启动阶段。由于安卓系统内核基于linux修剪而成,其引导和内核启动与linux基本相同,差异性是用户态init阶段和Zygote启动阶段,特别是...

    引言

    安卓系统的启动过程如下:
    在这里插入图片描述
    整个流程分为四个阶段,即引导阶段内核启动阶段用户态init阶段Zygote启动阶段。由于安卓系统内核基于linux修剪而成,其引导和内核启动与linux基本相同,差异性的是用户态init阶段和Zygote启动阶段,特别是Zygote阶段是安卓特有的。
    注 1本文中断解析用户态init阶段和Zygote启动阶段,引导阶段和内核启动阶段不做剖析。

    1 用户态init阶段

    1.1 流程概述

    用户态第一个进程init的入口main函数在/system/core/init/init.cpp文件中。整个流程大致归纳如下:
    在这里插入图片描述
    整个流程分为五步。首先,过滤非init进程选项,因为有些进行也是从该入口启动;第二步,盘断设备是否是第一次启动,若是进行初始化设置设备;第三步,初始化和设置系统属性、准备环境等设置;第四步,加载并执行rc文件;最后,进入监听循环。

    1.2 源码解读

    main函数主要流程概述如下:
    1 首先它判断第0个参数是否是ueventd、watchdogd,再判断第1个参数是否是subcontext。因为这个后续启动的这三个进程执行的binary和init进程是同一个。若都不是就真正进入我们的init阶段。其代码如下:

    545int main(int argc, char** argv) {
    546    if (!strcmp(basename(argv[0]), "ueventd")) {
    547        return ueventd_main(argc, argv);
    548    }
    549
    550    if (!strcmp(basename(argv[0]), "watchdogd")) {
    551        return watchdogd_main(argc, argv);
    552    }
    553
    554    if (argc > 1 && !strcmp(argv[1], "subcontext")) {
    555        InitKernelLogging(argv);
    556        const BuiltinFunctionMap function_map;
    557        return SubcontextMain(argc, argv, &function_map);
    558    }
    559
    560    if (REBOOT_BOOTLOADER_ON_PANIC) {
    561        InstallRebootSignalHandlers();
    562    }
    

    2 然后,再判断是否是第一次开机启动,若是,就执行第一次开机初始化,创建一些必须的文件、挂载一些目录、初始化selinux等。其代码如下:

    564    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
    565
    566    if (is_first_stage) {
    567        boot_clock::time_point start_time = boot_clock::now();
    568
    569        // Clear the umask.
    570        umask(0);
    

    3 初始化加载系统属性、对一些初始属性进行设置、启动selinux、最后启动属性服务等,其核心代码如下。属性服务的代码在/system/core/init/property_service.cpp中。下面的代码中693行调用了sigchld_handler_init函数,该函数在/system/core/init/sigchld_handler.cpp文件中,主要用于监听服务子进程死亡信号,然后重新拉起服务等功能,这也是为什么安卓能保证服务进程非正常死亡能重启的原因。

    658    property_init();
    659
    660    // If arguments are passed both on the command line and in DT,
    661    // properties set in DT always have priority over the command-line ones.
    662    process_kernel_dt();
    663    process_kernel_cmdline();
    664
    665    // Propagate the kernel variables to internal variables
    666    // used by init as well as the current required properties.
    667    export_kernel_boot_props();
    668
    669    // Make the time that init started available for bootstat to log.
    670    property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
    671    property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
    672
    673    // Set libavb version for Framework-only OTA match in Treble build.
    674    const char* avb_version = getenv("INIT_AVB_VERSION");
    675    if (avb_version) property_set("ro.boot.avb_version", avb_version);
    676
    677    // Clean up our environment.
    678    unsetenv("INIT_SECOND_STAGE");
    679    unsetenv("INIT_STARTED_AT");
    680    unsetenv("INIT_SELINUX_TOOK");
    681    unsetenv("INIT_AVB_VERSION");
    682
    683    // Now set up SELinux for second stage.
    684    SelinuxSetupKernelLogging();
    685    SelabelInitialize();
    686    SelinuxRestoreContext();
    687
    688    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    689    if (epoll_fd == -1) {
    690        PLOG(FATAL) << "epoll_create1 failed";
    691    }
    692
    693    sigchld_handler_init();
    694
    695    if (!IsRebootCapable()) {
    696        // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
    697        // In that case, receiving SIGTERM will cause the system to shut down.
    698        InstallSigtermHandler();
    699    }
    700
    701    property_load_boot_defaults();
    702    export_oem_lock_status();
    703    start_property_service();
    704    set_usb_controller();
    

    4 下面的代码是init进程启动服务、挂载文件等启动初始化的核心。首先是通过LoadBootScripts加载rc配置文件,该函数也在/system/core/init/init.cpp中,当ro.boot.init_rc属性没有设置的情况下,会加载/init.rc文件,后依次加载/system/etc/init、/product/etc/init、/odm/etc/init、/vendor/etc/init目录下的rc文件;然后依次通过函数ActionManager::QueueEventTrigger触发early-init、init、charger或late-init,这些系列action又会触发rc文件中的自定义action;然后去启动各种服务。

    706    const BuiltinFunctionMap function_map;
    707    Action::set_function_map(&function_map);
    708	   
    709    subcontexts = InitializeSubcontexts();
    710
    711    ActionManager& am = ActionManager::GetInstance();
    712    ServiceList& sm = ServiceList::GetInstance();
    713
    714    LoadBootScripts(am, sm);
    715
    716    // Turning this on and letting the INFO logging be discarded adds 0.2s to
    717    // Nexus 9 boot time, so it's disabled by default.
    718    if (false) DumpState();
    719
    720    am.QueueEventTrigger("early-init");
    721
    722    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
    723    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    724    // ... so that we can start queuing up actions that require stuff from /dev.
    725    am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
    726    am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
    727    am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
    728    am.QueueBuiltinAction(keychord_init_action, "keychord_init");
    729    am.QueueBuiltinAction(console_init_action, "console_init");
    730
    731    // Trigger all the boot actions to get us started.
    732    am.QueueEventTrigger("init");
    733
    734    // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
    735    // wasn't ready immediately after wait_for_coldboot_done
    736    am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
    737
    738    // Don't mount filesystems or start core system services in charger mode.
    739    std::string bootmode = GetProperty("ro.bootmode", "");
    740    if (bootmode == "charger") {
    741        am.QueueEventTrigger("charger");
    742    } else {
    743        am.QueueEventTrigger("late-init");
    744    }
    745
    746    // Run all property triggers based on current state of the properties.
    747    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
    

    5 最后,进入epoll循环监听事件并处理,例如当子服务进程非正常死亡后,相应的信号函数会往signal_write_fd中写入信息,然后由epoll轮询处理。

    749    while (true) {
    750        // By default, sleep until something happens.
    751        int epoll_timeout_ms = -1;
    752
    753        if (do_shutdown && !shutting_down) {
    754            do_shutdown = false;
    755            if (HandlePowerctlMessage(shutdown_command)) {
    756                shutting_down = true;
    757            }
    758        }
    759
    760        if (!(waiting_for_prop || Service::is_exec_service_running())) {
    761            am.ExecuteOneCommand();
    762        }
    763        if (!(waiting_for_prop || Service::is_exec_service_running())) {
    764            if (!shutting_down) {
    765                auto next_process_restart_time = RestartProcesses();
    766
    767                // If there's a process that needs restarting, wake up in time for that.
    768                if (next_process_restart_time) {
    769                    epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(
    770                                           *next_process_restart_time - boot_clock::now())
    771                                           .count();
    772                    if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
    773                }
    774            }
    775
    776            // If there's more work to do, wake up again immediately.
    777            if (am.HasMoreCommands()) epoll_timeout_ms = 0;
    778        }
    779
    780        epoll_event ev;
    781        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
    782        if (nr == -1) {
    783            PLOG(ERROR) << "epoll_wait failed";
    784        } else if (nr == 1) {
    785            ((void (*)()) ev.data.ptr)();
    786        }
    787    }
    

    2 Zygote启动阶段

    zygote的启动过程,后面补充。。。

    展开全文
  • 基于换模时间、缓冲区库存、看板容量、生产装配节拍比四个决策变量,建立看板系统模型, 分析该系统环境依赖性, 以装配线不中断为约束,求解不同状态下系统最优运行绩效. 最后,给出Y公司看板控制系统优化实例.结果...
  • 反编译器的基本原理以及它对逆向过程的影响。 本书适合软件逆向工程的从业人员以及软件开发者们阅读 第1部分 逆向101 第1章 基础 3 1.1 什么是逆向工程 3 1.2 软件逆向工程:逆向 4 1.3 逆向应用 4 1.3.1 与...
  • TCP传输三次握手: 首先发送端(前端)发送一带有SYN标志数据包给对方...3. 若在握手过程中某个阶段莫名中断,TCP协议会再次以相同方式发送相同数据包 断开一TCP连接则需要“次挥手”: 第一次挥...
    TCP传输的三次握手:
    首先发送端(前端)发送一个带有SYN标志的数据包给对方。
    1.  接收端(后端)收到后,回传一个带有SYN/ACK标志的数据包以表示传达确认信息。
    2.  发送端(前端)在回传一个带ACK标志的数据包,代表“握手”结束
    3.  若在握手过程中某个阶段莫名中断,TCP协议会再次以相同的方式发送相同的数据包
     
    断开一个TCP连接则需要“四次挥手”:
    第一次挥手:主动关闭方发送FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方,我已经不会再向你发送数据了(当然,在FIN包之前发送出去的数据,如果没有收到对应的ack确认报文,主动关闭方依然会重发这些数据),但是此时主动关闭方还可以接收数据
    第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与FIN占用一个序号)
    第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,就是告诉主动关闭方,我的数据已经发送完了,不会向你再发数据了。
    第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,四次挥手完成。

    转载于:https://www.cnblogs.com/jinbang/p/8658580.html

    展开全文
  • 答: 计算机网络发展过程大致经历了四个阶段。 第一阶段:(20世纪60年代)以单个计算机为中心面向终端计算机网络系统。这种网络系统是以批处理信息为主要目的。它缺点是:如果计算机负荷较重,会导致系统...
  • 19 事务 Redis通过MULTI、EXEC、WATCH等命令来实现事务功能。 基本概念:事务提供了一种将多个命令请求打包,然后一次性按顺序执行多个命令机制...经历三个阶段:事务开始、命令入队、事务执行 19.1.1 事务开始 M

    19 事务

    • Redis通过MULTI、EXEC、WATCH等命令来实现事务功能。
    • 基本概念:事务提供了一种将多个命令请求打包,然后一次性按顺序执行多个命令的机制,在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所有命令都执行完毕,然后再去处理其他客户端的命令请求。
    • 执行过程:事务首先以MULTI命令为开始,接着将多个命令放入事务当中,最后由EXEC命令将事务提交给服务器执行

    19.1 事务的实现

    • 经历三个阶段:事务开始、命令入队、事务执行

    19.1.1 事务开始

    • MULTI命令可以将客户端从非事务状态切换到事务状态,通过打开客户端flags属性中的REDIS_MULTI

    19.1.2 命令入队

    • 客户端处于非事务状态,客户端发送的命令会立即被服务器执行
    • 客户端处于事务状态,服务器会根据这个客户端发来的不同命令执行不同的操作
      • 命令:EXEC、DISCARD、WATCH、MULTI四个命令中的其中一个,服务器会立即执行这个命令
      • 命令:EXEC、DISCARD、WATCH、MULTI四个命令以外的命令,服务器并不立即执行这个命令,而是将这个命令放入一个事务队列中,然后向客户端返回QUEUED回复
    • 事务队列是先进先出的方式保存入队命令FIFO
    //code0: server.h
    typedef struct client {
        // ...
        multiState mstate;      /* MULTI/EXEC state */
        // ...
    }
    /* Client MULTI/EXEC state */
    typedef struct multiCmd {
        robj **argv;
        int argc;
        struct redisCommand *cmd;
    } multiCmd;
    
    typedef struct multiState {
        multiCmd *commands;     /* Array of MULTI commands */
        int count;              /* Total number of MULTI commands */
        int cmd_flags;          /* The accumulated command flags OR-ed together.
                                   So if at least a command has a given flag, it
                                   will be set in this field. */
        int cmd_inv_flags;      /* Same as cmd_flags, OR-ing the ~flags. so that it
                                   is possible to know if all the commands have a
                                   certain flag. */
        int minreplicas;        /* MINREPLICAS for synchronous replication */
        time_t minreplicas_timeout; /* MINREPLICAS timeout as unixtime. */
    } multiState;
    
    

    19.1.3 执行事务

    • 当一个处于事务状态的客户端向服务器发送EXEC命令时,这个命令会立即被服务器执行
    • 服务器会遍历这个客户端的事务队列,执行队列中保存的所有命令,最后将执行所得的结果全部返回给客户端
    //code1 multi.c
    void discardTransaction(client *c) {
        freeClientMultiState(c);
        initClientMultiState(c);
        c->flags &= ~(CLIENT_MULTI|CLIENT_DIRTY_CAS|CLIENT_DIRTY_EXEC);
        unwatchAllKeys(c);
    }
    
    /* Release all the resources associated with MULTI/EXEC state */
    void freeClientMultiState(client *c) {
        int j;
    
        for (j = 0; j < c->mstate.count; j++) {
            int i;
            multiCmd *mc = c->mstate.commands+j;
    
            for (i = 0; i < mc->argc; i++)
                decrRefCount(mc->argv[i]);
            zfree(mc->argv);
        }
        zfree(c->mstate.commands);
    }
    
    void execCommand(client *c) {
        int j;
        robj **orig_argv;
        int orig_argc;
        struct redisCommand *orig_cmd;
        int must_propagate = 0; /* Need to propagate MULTI/EXEC to AOF / slaves? */
        int was_master = server.masterhost == NULL;
    
        if (!(c->flags & CLIENT_MULTI)) {
            addReplyError(c,"EXEC without MULTI");
            return;
        }
    
        /* Check if we need to abort the EXEC because:
         * 1) Some WATCHed key was touched.
         * 2) There was a previous error while queueing commands.
         * A failed EXEC in the first case returns a multi bulk nil object
         * (technically it is not an error but a special behavior), while
         * in the second an EXECABORT error is returned. */
        if (c->flags & (CLIENT_DIRTY_CAS|CLIENT_DIRTY_EXEC)) {
            addReply(c, c->flags & CLIENT_DIRTY_EXEC ? shared.execaborterr :
                                                       shared.nullarray[c->resp]);
            discardTransaction(c);
            goto handle_monitor;
        }
    
        /* Exec all the queued commands */
        unwatchAllKeys(c); /* Unwatch ASAP otherwise we'll waste CPU cycles */
        orig_argv = c->argv;
        orig_argc = c->argc;
        orig_cmd = c->cmd;
        addReplyArrayLen(c,c->mstate.count);
        for (j = 0; j < c->mstate.count; j++) {
            c->argc = c->mstate.commands[j].argc;
            c->argv = c->mstate.commands[j].argv;
            c->cmd = c->mstate.commands[j].cmd;
    
            /* Propagate a MULTI request once we encounter the first command which
             * is not readonly nor an administrative one.
             * This way we'll deliver the MULTI/..../EXEC block as a whole and
             * both the AOF and the replication link will have the same consistency
             * and atomicity guarantees. */
            if (!must_propagate &&
                !server.loading &&
                !(c->cmd->flags & (CMD_READONLY|CMD_ADMIN)))
            {
                execCommandPropagateMulti(c);
                must_propagate = 1;
            }
    
            int acl_keypos;
            int acl_retval = ACLCheckCommandPerm(c,&acl_keypos);
            if (acl_retval != ACL_OK) {
                addACLLogEntry(c,acl_retval,acl_keypos,NULL);
                addReplyErrorFormat(c,
                    "-NOPERM ACLs rules changed between the moment the "
                    "transaction was accumulated and the EXEC call. "
                    "This command is no longer allowed for the "
                    "following reason: %s",
                    (acl_retval == ACL_DENIED_CMD) ?
                    "no permission to execute the command or subcommand" :
                    "no permission to touch the specified keys");
            } else {
                call(c,server.loading ? CMD_CALL_NONE : CMD_CALL_FULL);
            }
    
            /* Commands may alter argc/argv, restore mstate. */
            c->mstate.commands[j].argc = c->argc;
            c->mstate.commands[j].argv = c->argv;
            c->mstate.commands[j].cmd = c->cmd;
        }
        c->argv = orig_argv;
        c->argc = orig_argc;
        c->cmd = orig_cmd;
        discardTransaction(c);
    
        /* Make sure the EXEC command will be propagated as well if MULTI
         * was already propagated. */
        if (must_propagate) {
            int is_master = server.masterhost == NULL;
            server.dirty++;
            /* If inside the MULTI/EXEC block this instance was suddenly
             * switched from master to slave (using the SLAVEOF command), the
             * initial MULTI was propagated into the replication backlog, but the
             * rest was not. We need to make sure to at least terminate the
             * backlog with the final EXEC. */
            if (server.repl_backlog && was_master && !is_master) {
                char *execcmd = "*1\r\n$4\r\nEXEC\r\n";
                feedReplicationBacklog(execcmd,strlen(execcmd));
            }
        }
    
    handle_monitor:
        /* Send EXEC to clients waiting data from MONITOR. We do it here
         * since the natural order of commands execution is actually:
         * MUTLI, EXEC, ... commands inside transaction ...
         * Instead EXEC is flagged as CMD_SKIP_MONITOR in the command
         * table, and we do it here with correct ordering. */
        if (listLength(server.monitors) && !server.loading)
            replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc);
    }
    

    19.2 WATCH命令的作用

    • WATCH命令是一个乐观锁,在EXEC命令执行之前,监视任意数量的数据库键;在EXEC命令执行时,如果被监视的键至少有一个已经被修改过了,服务器将拒绝执行事务,并向客户端返回代表事务执行失败的空回复(nil)

    19.2.1 使用WATCH命令监视数据库键

    • 每个Redis数据库都保存着watched_keys字典,这个字典的键是某个被WATCH命令监视的数据库键,字典的值是一个链表,链表中记录所有监视相应数据库键的客户端
    //code2 server.h
    typedef struct redisDb {
        dict *dict;                 /* The keyspace for this DB */
        dict *expires;              /* Timeout of keys with a timeout set */
        dict *blocking_keys;        /* Keys with clients waiting for data (BLPOP)*/
        dict *ready_keys;           /* Blocked keys that received a PUSH */
        dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */
        int id;                     /* Database ID */
        long long avg_ttl;          /* Average TTL, just for stats */
        unsigned long expires_cursor; /* Cursor of the active expire cycle. */
        list *defrag_later;         /* List of key names to attempt to defrag one by one, gradually. */
    } redisDb;
    

    19.2.2 监视机制的触发

    • 所有对数据库进行修改的命令,比如SET、SADD、DEL、FLUSHDB、LPUSH执行结束后,会调用multi.c/touchWatchedKey函数对watched_keys进行检查,查看是否有客户端正在监视刚刚被命令修改过的数据库键,如果有,touchWatchedKey函数会将监视被修改键的客户端的REDIS_DIRTY_CAS标识打开,表示该客户端的事务安全性已经被破坏
    //code3 multi.c
    /* "Touch" a key, so that if this key is being WATCHed by some client the
     * next EXEC will fail. */
    void touchWatchedKey(redisDb *db, robj *key) {
        list *clients;
        listIter li;
        listNode *ln;
    
        if (dictSize(db->watched_keys) == 0) return;
        clients = dictFetchValue(db->watched_keys, key);
        if (!clients) return;
    
        /* Mark all the clients watching this key as CLIENT_DIRTY_CAS */
        /* Check if we are already watching for this key */
        listRewind(clients,&li);
        while((ln = listNext(&li))) {
            client *c = listNodeValue(ln);
    
            c->flags |= CLIENT_DIRTY_CAS;
        }
    }
    

    19.2.3 判断事务是否安全

    • 服务器收到客户端发来的EXEC命令,服务器会根据这个客户端是否打开CLIENT_DIRTY_CAS标识来决定是否执行事务
      • 如果客户端打开了,拒绝执行
      • 如果没有,服务器执行

    19.3 事务的ACID性质

    19.3.1 atomicity:原子性

    • 原子性概念:事务队列中的命令要么全部执行,要么一个都不执行
    • 事务回滚:程序或者数据处理错误,将程序或数据恢复到上一次正确状态的行为
    • Redis:不支持事件回滚机制rollback,即使事务队列中的某个命令在执行期间出现了错误,整个事务也会继续执行下去,直到所有事务队列的所有命令都被执行完毕

    19.3.2 consistency:一致性

    • 一致性概念:数据库执行事务之前是一致的,在事务执行之后,无论事务是否执行成功,数据库也应该是一致的
      • 一致:数据符合数据库本身的定义和要求,没有包含非法或者无效的错误数据
    • Redis为了保证事务的一致性,做了错误检测和对应的处理
      • 入队错误:如果命令不存在或者格式不正确,redis拒绝执行这个错误
      • 执行错误:命令实际执行时被触发(对数据库键执行了错误类型的操作等)
      • 服务停机:
        • 服务器运行在无持久化的内存模式下,重启之后数据库空白,符合数据库一致性
        • 服务器运行在RDB模式下,可以还原数据库到一致的状态
        • 服务器运行在AOF模式下,服务器可以根据AOF还原到一致的状态

    19.3.3 isolation:隔离性

    • 隔离性概念:数据库中有多个事务并发执行,各个事务之间也不会相互影响,而且在并发状态下执行的事务和串行执行的事务产生结果完全相同
    • Redis:单线程执行事务,且在执行事务期间不会对事务进行中断

    19.3.4 durability:持久性

    • 耐久性概念:当一个事务执行完毕后,执行这个事务所得的结果已经被保存到永久性存储介质中。即使服务器在事务执行完毕之后停机,执行事务所得的结果也不会丢失。
    • Redis事务的耐久性和Redis使用的持久化模式相关
      • 服务器运行在无持久化的内存模式下,事务不具有耐久性,重启之后数据库空白,包括事务数据在内的所有服务器数据都将丢失
      • 服务器运行在RDB模式下,服务器只有在特定的保存条件被满足时才会执行BGSAVE命令,对数据库进行保存操作,异步执行的BGSAVE不能保证事务数据第一时间被保存在硬盘里面,该RDB持久化模式下的事务也不具有耐久性
      • 服务器运行在AOF模式下,appendfsync选项为always时,程序总会在执行命令之后调用sync函数,将命令数据保存到硬盘里,该配置下的事务就有耐久性
        • 配置选项no-appendfsync-on-rewrite如果打开,即使AOF设置成always,事务也不具备耐久性【因为该选项打开过程中,BGSAVE或者BGREWRITEAOF执行时,服务器会暂停对AOF文件的同步,以减少I/O阻塞】
      • 服务器运行在AOF模式下,appendfsync选项为everysec时,程序会每秒同步一次命令数据到硬盘,停机如果发生在等待同步的那一秒,可能会造成事务数据丢失,该配置下的事务不具备耐久性
      • 服务器运行在AOF模式下,appendfsync选项为no时,程序会等待操作系统决定何时同步一次命令数据到硬盘,停机如果发生在等待同步过程中,可能会造成事务数据丢失,该配置下的事务不具备耐久性
      • 事务执行的最后一条命令设置成SAVE,可保证事务的耐久性【效率太低】
    展开全文
  • 答: 计算机网络发展过程大致经历了四个阶段。 第一阶段:(20世纪60年代)以单个计算机为中心面向终端计算机网络系统。这种网络系统是以批处理信息为主要目的。它缺点是:如果计算机负荷较重,会导致系统...
  • 通过我们已经学过知识,你可以编写一最简单程序输出一也许是程序世界中最有名词语: echo "Hello World!"; ?> First PHP page // Single line C++ style comment /* printing the message */ ...
  • 1.11.4 一独立领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一计划 1.12.3 阶段1:要制作什么? 1.12.4 阶段2:开始构建? 1.12.5 阶段3:正式创建 1.12.6 阶段4:校订 1.12.7 计划...
  • USB传输类型

    万次阅读 2012-11-14 21:31:34
    控制传输总共三个阶段,setup阶段、数据阶段和状态阶段,其中数据阶段是可选,而每个阶段都包含三个过程,即令牌过程、数据过程和握手过程。每个USB设备都必须具有控制传输功能,控制传输用于主机同设备控制端点...

    USB传输类型

    USB中有四种类型的端点,也就对应四种不同的传输方式,分别是控制传输、中断传输、同步传输和块传输。


    控制传输

    控制传输的读写时序如下:


    控制传输总共三个阶段,setup阶段、数据阶段和状态阶段,其中数据阶段是可选的,而每个阶段都包含三个过程,即令牌过程、数据过程和握手过程。每个USB设备都必须具有控制传输功能,控制传输用于主机同设备的控制端点进行通信,通过读取设备的配置信息来完成对设备的枚举和配置。


    setup阶段


    setup阶段首先是setup令牌,然后是数据过程,最后是状态过程,对于数据过程只能使用DATA0包,设备在接收到setup数据包之后,需要返回ACK信号,如果接收数据错误,设备是不会返回握手包。setup数据呢就是主机往设备发送的请求数据包,设备根据这个请求数据包来做相应的动作,例如:返回设备描述符或者直接进入状态阶段返回一个0长度的数据包。SETUP传输呢有点类似于OUT传输,只不过OUT传输发送的是OUT令牌,SETUP传输发送的是SETUP令牌。


    数据阶段

    如果是OUT传输呢,那么首先发送的是OUT令牌,如果IN传输呢,则发送的是IN令牌,然后是数据过程,数据过程必须以DATA1包开始,然后在DATA0DATA1之间交替,注意数据过程的方向必须是同一个方向,即要么都是IN传输,要么都是OUT传输。


    状态阶段

    状态阶段的传输方向同数据阶段的传输方向刚好相反,即数据阶段是IN传输呢,状态阶段就是OUT传输,数据阶段是OUT传输呢,状态阶段就是IN传输。如果没有数据阶段呢,那就是只能是IN传输。状态阶段的响应信息如图所示:


    状态阶段的数据过程呢使用的DATA1包,如果是控制写,设备在正确收到数据包之后将返回一个0长度的数据包。注意这个0长度数据和没有数据概念是不一样的,0长度数据有数据的包头,只是后面没有数据罢了。对于控制读,主机在接收数据之后,将返回ACK握手信息。


    中断传输

    中断传输呢分为INOUT传输,如果是IN传输,设备返回数据或者NAKSTALL握手信息。如果端点没有新的中断信息返回,在数据过程中设备返回的是NAK握手信息,如果此时端点已经被设置为暂停了,设备返回的是STALL握手信息,如果设备返回的是中断信息数据包,主机必须返回一个ACK握手信息给设备,如果数据数据接收错误,将不会返回握手信息。INOUT传输过程如图所示:


    中断传输一般用于这种具有固定速率、数据量少的数据传输,例如USB鼠标、键盘就是采用的中断传输。


    同步传输

    同步传输也叫做等时传输,也分为INOUT传输,但是注意没有握手过程,所以说它并不保证数据传输是否正确性,但是要保证数据传输的实时性,所以这种传输方式一般用于音频和视频流的数据传输,例如你的USB摄像头就是采用的这种传输方式,传输过程如下:



    块传输

    块传输也叫做批量传输,块传输并不追求数据传输的时间,但是必须保证数据传输的正确性,例如U盘就是采用的这种传输方式,传输过程如下:


    为了保证数据传输的正确性,USB采用的是错误检测机制和重试机制来确保数据传输正确,当然它也分三个过程,令牌过程、数据过程和握手过程,其中PING令牌和NYET令牌只用于高速设备。


    展开全文
  • 文件)管理者作为用户和计算机硬件之间的接口作为最接近硬件的层次总结操作系统的四个特征并发共享虚拟异步总结OS发展阶段手工操作阶段单道批处理系统多道批处理系统为何多道批处理系统能使资源利用率大幅提升分时...
  • 本文研究并设计了基于Android+HTML5在线认证检测系统,主要工作包括以下四个方面: (1)针对多窗口类浏览器模式问题,指出并分析了该问题存在原因,利用Activity运行机制,通过Fragment栈对主要模块Webview...
  • 其次运用于会展运作、营销和功能拓展,展馆信息、展会信息、参展商信息、采购商信息、招展过程和围绕展会企业相互讲信息沟通都可以通过网络实现。高效、充实、开放信息平台不仅有助于提高展览公司、展会...
  • ERP实施大体上分三个阶段:前期主要是基础数据准备,进行标准化;中期进行交接面界定,业务流程重组;后期是实施适应期,实行手工与计算机并行作业,逐步解决原手工作业对计算机作业不适应性。实施过程具体包括...
  • 用GCC编译过程可以被细分为四个阶段:预编译,编译,汇编,链接。 编译有线程文件要加 -lpthread 参数。 父进程等待子进程结束,可以使用函数 wait() 和 waitpid() 。 linux主要有两个信号安装函数,...
  • 详解Redis事务

    2021-01-17 11:24:11
    文章目录redis事务概念redis事务个阶段redis事务四大特性(ACID)redis中watch命令了解吗?总结 redis事务概念 Redis通过MULTI、EXEC、WATCH等命令来实现事务( transaction)功能。事务提供了一种将多个...
  • Linux内核源代码情景分析 (上下册 高清非扫描 )

    千次下载 热门讨论 2011-03-27 21:27:03
    2.3 几重要数据结构和函数 2.4 越界访问 2.5 用户堆栈扩展 2.6 物理页面使用和周转 2.7 物理页面分配 2.8 页面定期换出 2.9 页面换入 2.10 内核缓冲区管理 2.11 外部设备存储空间地址映射 2.12 ...
  • Linux系统初始化流程

    千次阅读 2016-11-04 23:08:39
    linux系统启动,指是...四个汇编程序:bootsect.S setup.S head.S entry.S init目录下main.c文件 主要查看init/main.c中start_kernel函数: 在系统启动过程中,主要关注一下几个方面: 中断系统及调度系统
  • 安全建设思考安全运维之术安全运维自动化...综合了解这些信息后,需要评估这个时候安全所处的阶段,可能还会做一下同行差距分析,然后才着手做安全规划,就需要引入企业安全建设有一份论,一般来说建设信息安全有四个
  • linux 内核源代码分析

    2013-07-26 21:11:21
    2.3 几重要数据结构和函数 2.4 越界访问 2.5 用户堆栈扩展 2.6 物理页面使用和周转 2.7 物理页面分配 2.8 页面定期换出 2. 9 页面换入 2.10 内核缓冲区管理 2.11 外部设备存储空间...
  • 2.3 几重要数据结构和函数 2.4 越界访问 2.5 用户堆栈扩展 2.6 物理页面使用和周转 2.7 物理页面分配 2.8 页面定期换出 2.9 页面换入 2.10 内核缓冲区管理 2.11 外部设备存储空间地址映射...
  • │ 高并发编程第二阶段44讲、被动引用和类加载过程的练习巩固训练题.mp4 │ 高并发编程第二阶段45讲、ClassLoader加载阶段发生的故事.mp4 │ 高并发编程第二阶段46讲、ClassLoader链接阶段(验证,准备,解析)...
  • │ 高并发编程第二阶段44讲、被动引用和类加载过程的练习巩固训练题.mp4 │ 高并发编程第二阶段45讲、ClassLoader加载阶段发生的故事.mp4 │ 高并发编程第二阶段46讲、ClassLoader链接阶段(验证,准备,解析)...
  • 软件测试规范

    2018-04-23 09:16:12
    5 .软件测试类型 ............................................................................................................................................ 6 1.模块测试 .............................
  • 时间:2018年1月15日 1.TCP三次握手与次挥手过程,各个状态名称与含义,TIME_WAIT作用?...若在某个阶段中断,TCP协议会再次以相同顺序发送相同数据包 次挥手:客户端发送FIN请求切断连接;服务端
  • jsr80 java 访问 usb

    2015-02-14 08:52:01
    1994年,一个由四个行业伙伴(Compaq、Intel、Microsoft 和 NEC)组成联盟开始制定 USB 协议。该协议最初目的是将 PC 与电话相连并提供容易扩展和重新配置 I/O 接口。1996年 1月,发表了 USB 规范第一个版本,...
  • 测试原则

    2014-05-26 23:25:43
    一,测试应该尽早进行,最好在需求阶段就开始介入,因为最严重错误不外乎是系统不能满足用户需求。 二,程序员应该避免检查自己程序,软件测试应该由第三方来负责。 三,设计测试用例时应考虑到合法输入和...
  • Linux内核情景分析

    2009-11-26 11:18:49
    2.3 几重要数据结构和函数 2.4 越界访问 2.5 用户堆栈扩展 2.6 物理页面使用和周转 2.7 物理页面分配 2.8 页面定期换出 2. 9 页面换入 2.10 内核缓冲区管理 2.11 外部设备存储空间地址...
  • 答: 计算机网络发展过程大致经历了四个阶段。 第一阶段:(20世纪60年代)以单个计算机为中心面向终端计算机网络系统。这种网络系统是以批处理信息为主要目的。它缺点是:如果计算机负荷较重,会导致系统...
  • 对于操作系统技术感兴趣,想要亲身体验编写操作系统过程的实践主义者,以及Minix、Linux源代码爱好者,都可以在本书中得到实践中所需的知识和思路。  本书以“动手写”为指导思想,只要是跟“动手写”操作系统有关...

空空如也

空空如也

1 2 3 4
收藏数 66
精华内容 26
关键字:

中断过程的四个阶段