红梦叉特色
fork功能
上层通过使用fork()函数创建新进程。
fork是什么?
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
pid_t pid;
char *message;
int n;
pid = fork();
if (pid < 0) {
perror("fork failed");
exit(1);
}
if (pid == 0) {
message = "This is the child\n";
n = 6;
} else {
message = "This is the parent\n";
n = 3;
}
for(; n > 0; n--) {
printf(message);
sleep(1);
}
return 0;
}
运行输出结果:
This is the child
This is the parent
This is the child
This is the parent
This is the child
This is the parent
This is the child
$ This is the child
This is the child
- pid < 0 fork 失败
- pid == 0 fork成功,是子进程的返回
- pid > 0 fork成功,是父进程的返回
- fork的返回值这样规定是有道理的。fork在子进程中返回0,子进程仍可以调用getpid函数得到自己的进程id,也可以调用getppid函数得到父进程的id。在父进程中用getpid可以得到自己的进程id,然而要想得到子进程的id,只有将fork的返回值记录下来,别无它法。
- 子进程并没有真正执行fork(),而是内核用了一个很巧妙的方法获得了返回值,并且将返回值硬生生的改写成了0,这是笔者认为fork的实现最精彩的部分
- fork() 是一个系统调用,因此会切换到SVC模式运行.在SVC栈中父进程复制出一个子进程,父进程和子进程的PCB信息相同,用户态代码和数据也相同.
fork 之后的代码父子进程都会执行,即代码段指向(PC寄存器)是一样的.实际上fork只被父进程调用了一次,子进程并没有执行fork函数,但是却获得了一个返回值,pid == 0;
子进程是从pid = fork() 后开始执行的,按理它不会在新任务栈中出现这些变量,而实际上后面又能顺利的使用这些变量,说明父进程当前任务的用户态的数据也复制了一份给子进程的新任务栈中.
-
被fork成功的子进程跑的首条代码指令是 pid = 0,这里的0是返回值,存放在R0寄存器中.说明父进程的任务上下文也进行了一次拷贝,父进程从内核态回到用户态时恢复的上下文和子进程的任务上下文是一样的,即 PC寄存器指向是一样的,如此才能确保在代码段相同的位置执行.
-
执行程序后 第一条打印的是This is the child说明 fork()中发生了一次调度,CPU切到了子进程的任务执行,sleep(1)的本质在系列篇中多次说过是任务主动放弃CPU的使用权,将自己挂入任务等待链表,由此发生一次任务调度,CPU切到父进程执行,才有了打印第二条的This is the parent,父进程的sleep(1)又切到子进程如此往返,直到 n = 0, 结束父子进程.
-
fork函数的特点概括起来就是“调用一次,返回两次”,在父进程中调用一次,在父进程和子进程中各返回一次
fork的调用流程
pid_t ret = fork();
musl-libc是面向上层提供的C-API
third_party\musl\src\process\fork.c
pid_t fork(void)
{
sigset_t set;
__fork_handler(-1);
__block_app_sigs(&set);
int need_locks = libc.need_locks > 0;
if (need_locks) {
__ldso_atfork(-1);
__inhibit_ptc();
for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
if (*atfork_locks[i]) LOCK(*atfork_locks[i]);
__malloc_atfork(-1);
__tl_lock();
}
pthread_t self=__pthread_self(), next=self->next;
pid_t ret = _Fork();//执行_Fork()
int errno_save = errno;
if (need_locks) {
if (!ret) {
for (pthread_t td=next; td!=self; td=td->next)
td->tid = -1;
if (__vmlock_lockptr) {
__vmlock_lockptr[0] = 0;
__vmlock_lockptr[1] = 0;
}
}
__tl_unlock();
__malloc_atfork(!ret);
for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
if (*atfork_locks[i])
if (ret) UNLOCK(*atfork_locks[i]);
else **atfork_locks[i] = 0;
__release_ptc();
__ldso_atfork(!ret);
}
__restore_sigs(&set);
__fork_handler(!ret);
if (ret<0) errno = errno_save;
return ret;
}
third_party\musl\src\process_Fork.c
pid_t _Fork(void)
{
pid_t ret;
sigset_t set;
__block_all_sigs(&set);
__aio_atfork(-1);
LOCK(__abort_lock);
#ifdef SYS_fork
//LiteOS-a内核系统调用SYS_fork
ret = __syscall(SYS_fork);
#else
ret = __syscall(SYS_clone, SIGCHLD, 0);
#endif
if (!ret) {
pthread_t self = __pthread_self();
self->tid = __syscall(SYS_gettid);
#ifdef __LITEOS_A__
self->pid = __syscall(SYS_getpid);
#else
self->pid = self->tid;
#endif
self->proc_tid = -1;
self->robust_list.off = 0;
self->robust_list.pending = 0;
self->next = self->prev = self;
__thread_list_lock = 0;
libc.threads_minus_1 = 0;
#ifndef __LITEOS__
__clear_proc_pid();
#endif
if (libc.need_locks) libc.need_locks = -1;
#ifdef __LITEOS_A__
libc.exit = 0;
signal(SIGSYS, arm_do_signal);
#endif
}
UNLOCK(__abort_lock);
__aio_atfork(!ret);
__restore_sigs(&set);
return __syscall_ret(ret);
}
kernel\liteos_a\syscall\process_syscall.c
//系统调用SYS_fork
int SysFork(void)
{
return OsClone(0, 0, 0);//本质就是克隆
}
kernel\liteos_a\kernel\base\core\los_process.c
LITE_OS_SEC_BSS LosProcessCB *g_processCBArray = NULL; ///< 进程池数组
LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_freeProcess;///< 空闲状态下的进程链表
LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_processRecycleList;///< 需要回收的进程列表
LITE_OS_SEC_BSS UINT32 g_processMaxNum;///< 进程最大数量,默认64个
#ifndef LOSCFG_PID_CONTAINER
LITE_OS_SEC_BSS ProcessGroup *g_processGroup = NULL;///< 全局进程组,负责管理所有进程组
#define OS_ROOT_PGRP(processCB) (g_processGroup)
#endif
......
/*!
* @brief OsClone 进程克隆
*
* @param flags
* @param size 进程主任务内核栈大小
* @param sp 进程主任务的入口函数
* @return
*
* @see
*/
LITE_OS_SEC_TEXT INT32 OsClone(UINT32 flags, UINTPTR sp, UINT32 size)
{
UINT32 cloneFlag = CLONE_PARENT | CLONE_THREAD | SIGCHLD;
#ifdef LOSCFG_KERNEL_CONTAINER
#ifdef LOSCFG_PID_CONTAINER
cloneFlag |= CLONE_NEWPID;
LosProcessCB *curr = OsCurrProcessGet();//获取当前进程
if (((flags & CLONE_NEWPID) != 0) && ((flags & (CLONE_PARENT | CLONE_THREAD)) != 0)) {
return -LOS_EINVAL;
}
//判断当前进程的pid容器和其子进程是否一致,一致则为false
if (OS_PROCESS_PID_FOR_CONTAINER_CHECK(curr) && ((flags & CLONE_NEWPID) != 0)) {
return -LOS_EINVAL;
}
if (OS_PROCESS_PID_FOR_CONTAINER_CHECK(curr) && ((flags & (CLONE_PARENT | CLONE_THREAD)) != 0)) {
return -LOS_EINVAL;
}
#endif
#ifdef LOSCFG_UTS_CONTAINER
cloneFlag |= CLONE_NEWUTS;
#endif
#ifdef LOSCFG_MNT_CONTAINER
cloneFlag |= CLONE_NEWNS;
#endif
#ifdef LOSCFG_IPC_CONTAINER
cloneFlag |= CLONE_NEWIPC;
if (((flags & CLONE_NEWIPC) != 0) && ((flags & CLONE_FILES) != 0)) {
return -LOS_EINVAL;
}
#endif
#ifdef LOSCFG_TIME_CONTAINER
cloneFlag |= CLONE_NEWTIME;
#endif
#ifdef LOSCFG_USER_CONTAINER
cloneFlag |= CLONE_NEWUSER;
#endif
#ifdef LOSCFG_NET_CONTAINER
cloneFlag |= CLONE_NEWNET;
#endif
#endif
if (flags & (~cloneFlag)) {
return -LOS_EOPNOTSUPP;
}
//拷贝进程
return OsCopyProcess(cloneFlag & flags, NULL, sp, size);
}
......
STATIC INT32 OsCopyProcess(UINT32 flags, const CHAR *name, UINTPTR sp, UINT32 size)
{
UINT32 ret, processID;
LosProcessCB *run = OsCurrProcessGet();//获取当前进程
LosProcessCB *child = OsGetFreePCB();//从进程池中申请一个进程控制块,鸿蒙进程池默认64
if (child == NULL) {
return -LOS_EAGAIN;
}
processID = child->processID;
ret = OsInitPCB(child, run->processMode, name);//初始化PCB(进程控制块)
if (ret != LOS_OK) {
goto ERROR_INIT;
}
#ifdef LOSCFG_KERNEL_CONTAINER
//创建子进程的container,并copy父进程的PID_CONTAINER,MNT_CONTAINER,IPC_CONTAINER,USER_CONTAINER,TIME_CONTAINER,NET_CONTAINER,UTS_CONTAINER给子进程
ret = OsCopyContainers(flags, child, run, &processID);
if (ret != LOS_OK) {
goto ERROR_INIT;
}
#ifdef LOSCFG_KERNEL_PLIMITS
//给子进程配置cgroups:
//pLimits是内核提供的一种可以限制单个进程或者多个进程所使用资源的机制,可以对cpu,内存等资源实现精细化控制。plimits的接口通过plimitsfs的伪文件系统提供。通过操作文件对进程及进程资源进行分组管理,通过配置plimits组内限制器Plimiter限制进程组的memory、sched等资源的使用
//在proc目录下支持plimits目录,支持ipc, pid, memory, devices, sched控制器
ret = OsPLimitsAddProcess(run->plimits, child);
if (ret != LOS_OK) {
goto ERROR_INIT;
}
#endif
#endif
ret = OsForkInitPCB(flags, child, name, sp, size);//初始化进程控制块
if (ret != LOS_OK) {
goto ERROR_INIT;
}
ret = OsCopyProcessResources(flags, child, run);//拷贝进程的资源,包括虚拟空间,文件,安全,IPC ==
if (ret != LOS_OK) {
goto ERROR_TASK;
}
ret = OsChildSetProcessGroupAndSched(child, run);//设置进程组和加入进程调度就绪队列
if (ret != LOS_OK) {
goto ERROR_TASK;
}
LOS_MpSchedule(OS_MP_CPU_ALL);//给各CPU发送准备接受调度信号
if (OS_SCHEDULER_ACTIVE) {//当前CPU core处于活动状态
LOS_Schedule();// 申请调度
}
return processID;
ERROR_TASK:
(VOID)LOS_TaskDelete(child->threadGroup->taskID);
ERROR_INIT:
OsDeInitPCB(child);
return -ret;
}
......
STATIC LosProcessCB *OsGetFreePCB(VOID)
{
LosProcessCB *processCB = NULL;
UINT32 intSave;
//申请调度自旋锁,禁止调度
SCHEDULER_LOCK(intSave);
//判断空闲状态下的进程链表是否为空
if (LOS_ListEmpty(&g_freeProcess)) {
SCHEDULER_UNLOCK(intSave);
PRINT_ERR("No idle PCB in the system!\n");
return NULL;
}
//LOS_DL_LIST_FIRST(&g_freeProcess) 从链表中取出最头部的节点
//OS_PCB_FROM_PENDLIST内部调用LOS_DL_LIST_ENTRY,根据结构体成员地址, 类型,成员名,退出结构体的首地址并强制转换
//具体可看openharmony内核中特殊双向链表的遍历读取操作
processCB = OS_PCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_freeProcess));
//pendList->进程所属的阻塞列表,如果因拿锁失败,就由此节点挂到等锁链表上。
//从等锁链表中将自己删除
LOS_ListDelete(&processCB->pendList);
//释放调度自旋锁,允许调度
SCHEDULER_UNLOCK(intSave);
return processCB;
}
......
/*! 初始化PCB(进程控制块)*/
STATIC UINT32 OsInitPCB(LosProcessCB *processCB, UINT32 mode, const CHAR *name)
{
processCB->processMode = mode; //用户态进程还是内核态进程
processCB->processStatus = OS_PROCESS_STATUS_INIT; //进程初始状态
processCB->parentProcess = NULL; //父进程
processCB->threadGroup = NULL; //任务组
processCB->umask = OS_PROCESS_DEFAULT_UMASK; //掩码
processCB->timerID = (timer_t)(UINTPTR)MAX_INVALID_TIMER_VID;
//LOS_ListInit 初始化双向链表
LOS_ListInit(&processCB->threadSiblingList);//初始化进程的任务链表,上面挂的都是由此fork的子线程 见于 OsTaskCBInit LOS_ListTailInsert(&(processCB->threadSiblingList), &(taskCB->threadList));
//拷贝父亲大人的遗传基因信息
LOS_ListInit(&processCB->childrenList); //初始化子进程链表,上面挂的都是由此fork的子进程 见于 OsCopyParent LOS_ListTailInsert(&parentProcessCB->childrenList, &childProcessCB->siblingList);
/*
* 一个进程的自然消亡过程,参数是当前运行的任务
*/
LOS_ListInit(&processCB->exitChildList); //初始化记录退出子进程链表,上面挂的是哪些exit 见于 OsProcessNaturalExit LOS_ListTailInsert(&parentCB->exitChildList, &processCB->siblingList);
/*!
* 将任务挂入进程的waitList链表,表示这个任务在等待某个进程的退出
* 当被等待进程退出时候会将自己挂到父进程的退出子进程链表和进程组的退出进程链表.
*/
LOS_ListInit(&(processCB->waitList)); //初始化等待任务链表 上面挂的是处于等待的 见于 OsWaitInsertWaitLIstInOrder LOS_ListHeadInsert(&processCB->waitList, &runTask->pendList);
#ifdef LOSCFG_KERNEL_VM
//processCB->processMode == OS_USER_MODE
if (OsProcessIsUserMode(processCB)) {//如果是用户态进程
processCB->vmSpace = OsCreateUserVmSpace();//创建用户空间
if (processCB->vmSpace == NULL) {
processCB->processStatus = OS_PROCESS_FLAG_UNUSED;
return LOS_ENOMEM;
}
} else {
processCB->vmSpace = LOS_GetKVmSpace();//从这里也可以看出,所有内核态进程是共享一个进程空间的
}//在鸿蒙内核态进程只有kprocess 和 kidle 两个
#endif
#ifdef LOSCFG_KERNEL_CPUP
//进程的cpu使用
processCB->processCpup = (OsCpupBase *)LOS_MemAlloc(m_aucSysMem1, sizeof(OsCpupBase));
if (processCB->processCpup == NULL) {
return LOS_ENOMEM;
}
(VOID)memset_s(processCB->processCpup, sizeof(OsCpupBase), 0, sizeof(OsCpupBase));
#endif
#ifdef LOSCFG_SECURITY_VID
//进程vid相关的初始化
status_t status = VidMapListInit(processCB);
if (status != LOS_OK) {
return LOS_ENOMEM;
}
#endif
#ifdef LOSCFG_SECURITY_CAPABILITY
OsInitCapability(processCB);//初始化进程安全相关功能
#endif
//配置进程名字
if (OsSetProcessName(processCB, name) != LOS_OK) {
return LOS_ENOMEM;
}
return LOS_OK;
}
......
UINT32 OsSetProcessName(LosProcessCB *processCB, const CHAR *name)
{
errno_t errRet;
if (processCB == NULL) {
return LOS_EINVAL;
}
if (name != NULL) {
errRet = strncpy_s(processCB->processName, OS_PCB_NAME_LEN, name, OS_PCB_NAME_LEN - 1);
if (errRet == EOK) {
return LOS_OK;
}
}
switch (processCB->processMode) {
case OS_KERNEL_MODE:
errRet = snprintf_s(processCB->processName, OS_PCB_NAME_LEN, OS_PCB_NAME_LEN - 1,
"KerProcess%u", processCB->processID);
break;
default:
errRet = snprintf_s(processCB->processName, OS_PCB_NAME_LEN, OS_PCB_NAME_LEN - 1,
"UserProcess%u", processCB->processID);
break;
}
if (errRet < 0) {
return LOS_NOK;
}
return LOS_OK;
}
.....
STATIC UINT32 OsForkInitPCB(UINT32 flags, LosProcessCB *child, const CHAR *name, UINTPTR sp, UINT32 size)
{
UINT32 ret;
LosProcessCB *run = OsCurrProcessGet();//获取当前进程
ret = OsCopyParent(flags, child, run);//拷贝当前运行的父进程的信息给子进程
if (ret != LOS_OK) {
return ret;
}
//拷贝任务,设置任务入口函数,栈大小
return OsCopyTask(flags, child, name, sp, size);
}
......
STATIC UINT32 OsCopyParent(UINT32 flags, LosProcessCB *childProcessCB, LosProcessCB *runProcessCB)
{
UINT32 intSave;
LosProcessCB *parentProcessCB = NULL;
SCHEDULER_LOCK(intSave);
if (childProcessCB->parentProcess == NULL) {
if (flags & CLONE_PARENT) {
//如果需要copy父进程的父进程信息(childProcessCB 和 runProcessCB就是兄弟关系啦)
parentProcessCB = runProcessCB->parentProcess;
} else {
parentProcessCB = runProcessCB;
}
childProcessCB->parentProcess = parentProcessCB;
//通过兄弟姐妹节点,挂到父进程的子进程链表尾部(siblingList链表中的所有进程来自同一个父进程)
LOS_ListTailInsert(&parentProcessCB->childrenList, &childProcessCB->siblingList);
}
if (childProcessCB->pgroup == NULL) {
//copy父进程的进程组
childProcessCB->pgroup = parentProcessCB->pgroup;
//将自己的进程组成员插入到父进程进程组链表中
LOS_ListTailInsert(&parentProcessCB->pgroup->processList, &childProcessCB->subordinateGroupList);
}
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
......
/**
*不管是内核态的任务还是用户态的任务,于切换而言是统一处理,一视同仁的,因为切换是需要换栈运行,寄存器有限,需要频繁的复用,这就需要将当前寄存器值先保存到任务自己的栈中,以便别人用完了轮到自己再用时恢复寄存器当时的值,确保老任务还能继续跑下去. 而保存寄存器顺序的结构体叫:任务上下文(TaskContext)
*/
/**
* OsCopyTask这个很重要,拷贝父进程当前执行的任务数据给子进程的新任务,真正让CPU干活的是任务(线程),所以子进程需要创建一个新任务 LOS_TaskCreateOnly来接受当前任务的数据,这个数据包括栈的数据,运行代码段指向,OsUserCloneParentStack将用户态的上下文数据TaskContext拷贝到子进程新任务的栈底位置, 也就是说新任务运行栈中此时只有上下文的数据.而且有最最最重要的一句代码 context->R[0] = 0; 强制性的将未来恢复上下文R0寄存器的数据改成了0, 这意味着调度算法切到子进程的任务后, 任务干的第一件事是恢复上下文,届时R0寄存器的值变成0,而R0=0意味着什么? 同时LR/SP寄存器的值也和父进程的一样.这又意味着什么?
其实返回值就是存在R0寄存器中,A()->B(),A拿B的返回值只认R0的数据,读到什么就是什么返回值,而R0寄存器值等于0,等同于获得返回值为0, 而LR寄存器所指向的指令是pid=返回值, sp寄存器记录了栈中的开始计算的位置,如此完全还原了父进程调用fork()前的运行场景,唯一的区别是改变了R0寄存器的值,所以才有了
pid = 0;//fork()的返回值,注意子进程并没有执行fork(),它只是通过恢复上下文获得了一个返回值.
if (pid == 0) {
message = "This is the child\n";
n = 6;
}
由此确保了这是子进程的返回
*/
STATIC UINT32 OsCopyTask(UINT32 flags, LosProcessCB *childProcessCB, const CHAR *name, UINTPTR entry, UINT32 size)
{
LosTaskCB *runTask = OsCurrTaskGet();
TSK_INIT_PARAM_S taskParam = { 0 };
UINT32 ret, taskID, intSave;
SchedParam param = { 0 };
taskParam.pcName = (CHAR *)name;
GetCopyTaskParam(childProcessCB, entry, size, &taskParam, ¶m);
//子进程创建任务
ret = LOS_TaskCreateOnly(&taskID, &taskParam);
if (ret != LOS_OK) {
if (ret == LOS_ERRNO_TSK_TCB_UNAVAILABLE) {
return LOS_EAGAIN;
}
return LOS_ENOMEM;
}
LosTaskCB *childTaskCB = childProcessCB->threadGroup;
childTaskCB->taskStatus = runTask->taskStatus;//任务状态先同步,注意这里是赋值操作. ...01101001
childTaskCB->ops->schedParamModify(childTaskCB, ¶m);
if (childTaskCB->taskStatus & OS_TASK_STATUS_RUNNING) {//因只能有一个运行的task,所以如果一样要改4号位
childTaskCB->taskStatus &= ~OS_TASK_STATUS_RUNNING;//将四号位清0 ,变成 ...01100001
} else {//非运行状态下会发生什么?
if (OS_SCHEDULER_ACTIVE) {//克隆线程发生错误未运行
LOS_Panic("Clone thread status not running error status: 0x%x\n", childTaskCB->taskStatus);
}
childTaskCB->taskStatus &= ~OS_TASK_STATUS_UNUSED;//干净的Task
}
if (OsProcessIsUserMode(childProcessCB)) {//是否是用户进程
SCHEDULER_LOCK(intSave);
//copy父进程的栈数据
OsUserCloneParentStack(childTaskCB->stackPointer, entry, runTask->topOfStack, runTask->stackSize);
SCHEDULER_UNLOCK(intSave);
}
return LOS_OK;
}
......
/// 拷贝进程资源
STATIC UINT32 OsCopyProcessResources(UINT32 flags, LosProcessCB *child, LosProcessCB *run)
{
UINT32 ret;
ret = OsCopyUser(child, run);//拷贝用户信息
if (ret != LOS_OK) {
return ret;
}
ret = OsCopyMM(flags, child, run);//拷贝虚拟空间
if (ret != LOS_OK) {
return ret;
}
ret = OsCopyFile(flags, child, run);//拷贝文件信息
if (ret != LOS_OK) {
return ret;
}
#ifdef LOSCFG_KERNEL_LITEIPC
if (run->ipcInfo != NULL) { //重新初始化IPC池
child->ipcInfo = LiteIpcPoolReInit((const ProcIpcInfo *)(run->ipcInfo));//@note_good 将沿用用户态空间地址(即线性区地址)
if (child->ipcInfo == NULL) {//因为整个进程虚拟空间都是拷贝的,ipc的用户态虚拟地址当然可以拷贝,但因进程不同了,所以需要重新申请ipc池和重新映射池中两个地址uvaddr和kvaddr
return LOS_ENOMEM;
}
}
#endif
#ifdef LOSCFG_SECURITY_CAPABILITY
OsCopyCapability(run, child);//拷贝安全能力
#endif
return LOS_OK;
}
......
/// 拷贝用户信息 直接用memcpy_s
STATIC UINT32 OsCopyUser(LosProcessCB *childCB, LosProcessCB *parentCB)
{
#ifdef LOSCFG_SECURITY_CAPABILITY
UINT32 size = sizeof(User) + sizeof(UINT32) * (parentCB->user->groupNumber - 1);
childCB->user = LOS_MemAlloc(m_aucSysMem1, size);
if (childCB->user == NULL) {
return LOS_ENOMEM;
}
(VOID)memcpy_s(childCB->user, size, parentCB->user, size);
#endif
return LOS_OK;
}
//拷贝虚拟空间
STATIC UINT32 OsCopyMM(UINT32 flags, LosProcessCB *childProcessCB, LosProcessCB *runProcessCB)
{
status_t status;
UINT32 intSave;
if (!OsProcessIsUserMode(childProcessCB)) {//不是用户模式,直接返回,内核虚拟空间只有一个,无需COPY !!!
return LOS_OK;
}
if (flags & CLONE_VM) {//贴有虚拟内存的标签
SCHEDULER_LOCK(intSave);
childProcessCB->vmSpace->archMmu.virtTtb = runProcessCB->vmSpace->archMmu.virtTtb;//TTB虚拟地址基地址,即L1表存放位置,virtTtb是个指针,进程的虚拟空间是指定的范围的
childProcessCB->vmSpace->archMmu.physTtb = runProcessCB->vmSpace->archMmu.physTtb;//TTB物理地址基地址,physTtb是个值,取决于运行时映射到物理内存的具体哪个位置.
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
//虚拟内存空间拷贝,以及物理内存的映射
status = LOS_VmSpaceClone(flags, runProcessCB->vmSpace, childProcessCB->vmSpace);//虚拟空间clone
if (status != LOS_OK) {
return LOS_ENOMEM;
}
return LOS_OK;
}
/// 拷贝进程文件描述符(proc_fd)信息
STATIC UINT32 OsCopyFile(UINT32 flags, LosProcessCB *childProcessCB, LosProcessCB *runProcessCB)
{
#ifdef LOSCFG_FS_VFS //如果开启了虚拟文件宏(每个进程都有属于自己的文件管理器,记录对文件的操作<一个文件可以被多个进程操作 >)
if (flags & CLONE_FILES) {
//如果flag是CLONE_FILES,则copy父进程所持有的所有文件
childProcessCB->files = runProcessCB->files;
} else {
#ifdef LOSCFG_IPC_CONTAINER
if (flags & CLONE_NEWIPC) {
//记录当前进程任务(LosTaskCB)的cloneIpc为true
OsCurrTaskGet()->cloneIpc = TRUE;
}
#endif
//如果flag不是CLONE_FILES,则重新分配申请分配一个文件,copy runProcessCB->files一些信息给到新申请的文件
childProcessCB->files = dup_fd(runProcessCB->files);
#ifdef LOSCFG_IPC_CONTAINER
OsCurrTaskGet()->cloneIpc = FALSE;
#endif
}
if (childProcessCB->files == NULL) {
return LOS_ENOMEM;
}
#ifdef LOSCFG_PROC_PROCESS_DIR
//根据进程的pid创建进程目录(/proc/procProcessName)
INT32 ret = ProcCreateProcessDir(OsGetRootPid(childProcessCB), (UINTPTR)childProcessCB);
if (ret < 0) {
PRINT_ERR("ProcCreateProcessDir failed, pid = %u\n", childProcessCB->processID);
return LOS_EBADF;
}
#endif
#endif
childProcessCB->consoleID = runProcessCB->consoleID;//控制台也是文件
childProcessCB->umask = runProcessCB->umask;//进程掩码
return LOS_OK;
}
......
//设置进程组和加入进程调度就绪队列
STATIC UINT32 OsChildSetProcessGroupAndSched(LosProcessCB *child, LosProcessCB *run)
{
UINT32 intSave;
UINT32 ret;
ProcessGroup *pgroup = NULL;
SCHEDULER_LOCK(intSave);
//(pgroup)->pgroupLeader == OS_USER_PRIVILEGE_PROCESS_GROUP
//OS_USER_PRIVILEGE_PROCESS_GROUP为OsGetUserInitProcess()即init进程
//如果进程组属于init进程
if ((UINTPTR)OS_GET_PGROUP_LEADER(run->pgroup) == OS_USER_PRIVILEGE_PROCESS_GROUP) {
ret = OsSetProcessGroupIDUnsafe(child->processID, child->processID, &pgroup);
if (ret != LOS_OK) {
SCHEDULER_UNLOCK(intSave);
return LOS_ENOMEM;
}
}
//进程状态标记为初始化
child->processStatus &= ~OS_PROCESS_STATUS_INIT;
LosTaskCB *taskCB = child->threadGroup;//任务组
//将当前的任务入队(OsSchedRunqueue根据cpu id获取的对应的调度队列)
taskCB->ops->enqueue(OsSchedRunqueue(), taskCB);
SCHEDULER_UNLOCK(intSave);
(VOID)LOS_MemFree(m_aucSysMem1, pgroup);
return LOS_OK;
}
......
STATIC UINT32 OsSetProcessGroupIDUnsafe(UINT32 pid, UINT32 gid, ProcessGroup **pgroup)
{
LosProcessCB *processCB = OS_PCB_FROM_PID(pid);//根据进程id获取对应的进程控制块
ProcessGroup *rootPGroup = OS_ROOT_PGRP(OsCurrProcessGet());//获取当前进程的根进程组
LosProcessCB *pgroupCB = OS_PCB_FROM_PID(gid);//根据进程组id获取对应的进程控制块
UINT32 ret = OsSetProcessGroupCheck(processCB, pgroupCB);//进行安全检查,确保进程被移动到进程组
if (ret != LOS_OK) {
return ret;
}
//如果目标进程已经是目标进程组的领导,则返回成功
if (OS_GET_PGROUP_LEADER(processCB->pgroup) == pgroupCB) {
return LOS_OK;
}
ProcessGroup *oldPGroup = processCB->pgroup;
//使目标进程退出当前进程组
ExitProcessGroup(processCB, pgroup);
//根据进程组id查找新的进程组
ProcessGroup *newPGroup = OsFindProcessGroup(gid);
if (newPGroup != NULL) {
//将进程的进程组成员插入到新的进程组进程链表里面
LOS_ListTailInsert(&newPGroup->processList, &processCB->subordinateGroupList);
processCB->pgroup = newPGroup;
return LOS_OK;
}
//如果没找到进程组,则创建一个新的进程组
newPGroup = OsCreateProcessGroup(pgroupCB);
if (newPGroup == NULL) {
//如果创建失败,则将目标进程重新添加到原始的进程组中
LOS_ListTailInsert(&oldPGroup->processList, &processCB->subordinateGroupList);
processCB->pgroup = oldPGroup;
if (*pgroup != NULL) {
LOS_ListTailInsert(&rootPGroup->groupList, &oldPGroup->groupList);
processCB = OS_GET_PGROUP_LEADER(oldPGroup);
processCB->processStatus |= OS_PROCESS_FLAG_GROUP_LEADER;
*pgroup = NULL;
}
return LOS_EPERM;
}
return LOS_OK;
}
kernel\liteos_a\kernel\base\vm\los_vm_map.c
LosVmSpace *OsCreateUserVmSpace(VOID)
{
BOOL retVal = FALSE;
//从指定动态内存池中申请size长度的内存
//m_aucSysMem0 内存池基地址
//当平台不支持异常交互功能时候,m_aucSysMem0和m_aucSysMem1的起始地址相同,用于减少内存碎片,简化内存管理逻辑
LosVmSpace *space = LOS_MemAlloc(m_aucSysMem0, sizeof(LosVmSpace));
if (space == NULL) {
return NULL;
}
//分配一个物理页用于存储L1页表 4G虚拟内存分成 (4096*1M)
//申请的是一页地址连续的物理内存
VADDR_T *ttb = LOS_PhysPagesAllocContiguous(1);
if (ttb == NULL) {
//释放内存
(VOID)LOS_MemFree(m_aucSysMem0, space);
return NULL;
}
//初始化申请ttb内存 值为0
//PAGE_SZIE 为4kb(0x1000U)
(VOID)memset_s(ttb, PAGE_SIZE, 0, PAGE_SIZE);
//初始化vmSpace 的size mapSize headSize等
//将节点添加到链表中 LOS_ListAdd(&g_vmSpaceList, &vmSpace->node);
//以及初始化MMU(内存管理单元,用于在CPU和内存之间实现虚拟内存管理,将虚拟地址转换为物理地址)硬件模块
retVal = OsUserVmSpaceInit(space, ttb);
//通过虚拟地址拿到page
LosVmPage *vmPage = OsVmVaddrToPage(ttb);
if ((retVal == FALSE) || (vmPage == NULL)) {
//释放内存
(VOID)LOS_MemFree(m_aucSysMem0, space);
//释放地址连续的物理内存
LOS_PhysPagesFreeContiguous(ttb, 1);
return NULL;
}
//将空间映射页表挂在 空间的mmu L1页表, L1为表头
LOS_ListAdd(&space->archMmu.ptList, &(vmPage->node));
return space;
}
......
STATUS_T LOS_VmSpaceClone(UINT32 cloneFlags, LosVmSpace *oldVmSpace, LosVmSpace *newVmSpace)
{
LosRbNode *pstRbNode = NULL; //地址区间红黑树节点
LosRbNode *pstRbNodeNext = NULL; //地址区间下一个红黑树节点
STATUS_T ret = LOS_OK;
PADDR_T paddr;
VADDR_T vaddr;
LosVmPage *page = NULL;//物理内存页
UINT32 flags, i, intSave, numPages;
//判断新旧两个虚拟内存空间是否为NULL
if ((OsVmSpaceParamCheck(oldVmSpace) == FALSE) || (OsVmSpaceParamCheck(newVmSpace) == FALSE)) {
return LOS_ERRNO_VM_INVALID_ARGS;
}
//判断地址区间的红黑树根节点的ulNodes是否为0,以及要拷贝的虚拟内存空间为内核虚拟空间
if ((OsIsVmRegionEmpty(oldVmSpace) == TRUE) || (oldVmSpace == &g_kVmSpace)) {
return LOS_ERRNO_VM_INVALID_ARGS;
}
/* search the region list */
newVmSpace->mapBase = oldVmSpace->mapBase;//地址空间的映射区开始地址
newVmSpace->heapBase = oldVmSpace->heapBase;//地址空间的堆开始地址
newVmSpace->heapNow = oldVmSpace->heapNow;//地址空间的堆现在的地址
(VOID)LOS_MuxAcquire(&oldVmSpace->regionMux);//申请地址区间的红黑树的互斥锁
//如下使用:红黑树的宏对RB_SCAN_SAFE和RB_SCAN_SAFE_END从第一个树节点循环遍历
RB_SCAN_SAFE(&oldVmSpace->regionRbTree, pstRbNode, pstRbNodeNext)
LosVmMapRegion *oldRegion = (LosVmMapRegion *)pstRbNode;
#if defined(LOSCFG_KERNEL_SHM) && defined(LOSCFG_IPC_CONTAINER)
//如果当前地址区间的地址区间标记为共享内存的地址区间标记以及需要clone ipc信息,则继续遍历下一个红黑树节点
if ((oldRegion->regionFlags & VM_MAP_REGION_FLAG_SHM) && (cloneFlags & CLONE_NEWIPC)) {
continue;
}
#endif
//从地址空间newVmSpace中申请空闲的虚拟地址区间
//函数主要实现(LOS_RegionAlloc为这个函数)
//⑴处如果指定的虚拟地址为空,则调用函数OsAllocRange()申请内存。
//⑵如果指定的虚拟地址不为空,则调用函数OsAllocSpecificRange申请虚拟内存,下文会详细分析这2个申请函数。
//⑶处创建虚拟内存地址区间,然后指定地址区间的地址空间为当前空间vmSpace。
//⑷处把创建的地址区间插入地址空间的红黑树中。
LosVmMapRegion *newRegion = OsVmRegionDup(newVmSpace, oldRegion, oldRegion->range.base(虚拟内存地址区间开始地址), oldRegion->range.size(虚拟内存地址区间大小);
if (newRegion == NULL) {
VM_ERR("dup new region failed");
ret = LOS_ERRNO_VM_NO_MEMORY;
break;
}
#ifdef LOSCFG_KERNEL_SHM
//如果当前地址区间的地址区间标记为共享内存的地址区间标记
if (oldRegion->regionFlags & VM_MAP_REGION_FLAG_SHM) {
//fork共享内存,编译下个红黑树节点
OsShmFork(newVmSpace, oldRegion, newRegion);
continue;
}
#endif
//如果copy的地址内存空间的地址区间和当前节点的地址区间一致
if (oldRegion == oldVmSpace->heap) {
newVmSpace->heap = newRegion;
}
//PAGE_SHIFT 为12(即页大小为4KB)
//根据对应的虚拟内存地址区间大小获取对应的页数(如虚拟内存地址区间大小为8KB,转换的页数为2)
numPages = newRegion->range.size >> PAGE_SHIFT;
for (i = 0; i < numPages; i++) {
//计算每页的起始虚拟地址vaddr
vaddr = newRegion->range.base + (i << PAGE_SHIFT);
//获取对应物理地址paddr以及flag
if (LOS_ArchMmuQuery(&oldVmSpace->archMmu, vaddr, &paddr, &flags) != LOS_OK) {
continue;
}
//获取对应的物理页
page = LOS_VmPageGet(paddr);
if (page != NULL) {
//刷新内存页的引用计数
LOS_AtomicInc(&page->refCounts);
}
if (flags & VM_MAP_REGION_FLAG_PERM_WRITE) {
LOS_ArchMmuUnmap(&oldVmSpace->archMmu, vaddr, 1);
LOS_ArchMmuMap(&oldVmSpace->archMmu, vaddr, paddr, 1, flags & ~VM_MAP_REGION_FLAG_PERM_WRITE);
}
//用于映射进程空间虚拟地址区间与物理地址区间
LOS_ArchMmuMap(&newVmSpace->archMmu, vaddr, paddr, 1, flags & ~VM_MAP_REGION_FLAG_PERM_WRITE);
#ifdef LOSCFG_FS_VFS
//如果开启了虚拟文件系统宏,并且地址区间是有效的文件类型
if (LOS_IsRegionFileValid(oldRegion)) {
LosFilePage *fpage = NULL;
//申请映射自旋锁
LOS_SpinLockSave(&oldRegion->unTypeData.rf.vnode->mapping.list_lock, &intSave);
fpage = OsFindGetEntry(&oldRegion->unTypeData.rf.vnode->mapping, newRegion->pgOff + i);
if ((fpage != NULL) && (fpage->vmPage == page)) { /* cow page no need map */
OsAddMapInfo(fpage, &newVmSpace->archMmu, vaddr);
}
//释放映射自旋锁
LOS_SpinUnlockRestore(&oldRegion->unTypeData.rf.vnode->mapping.list_lock, intSave);
}
#endif
}
RB_SCAN_SAFE_END(&oldVmSpace->regionRbTree, pstRbNode, pstRbNodeNext)
(VOID)LOS_MuxRelease(&oldVmSpace->regionMux);
return ret;
}
kernel\liteos_a\arch\arm\arm\src\los_hw.c
VOID OsUserCloneParentStack(VOID *childStack, UINTPTR sp, UINTPTR parentTopOfStack, UINT32 parentStackSize)
{
LosTaskCB *task = OsCurrTaskGet();
sig_cb *sigcb = &task->sig;
VOID *cloneStack = NULL;
if (sigcb->sigContext != NULL) {
cloneStack = (VOID *)((UINTPTR)sigcb->sigContext - sizeof(TaskContext));
} else {
cloneStack = (VOID *)(((UINTPTR)parentTopOfStack + parentStackSize) - sizeof(TaskContext));
}
//将用户态的上下文数据TaskContext拷贝到子进程新任务的栈底位置, 也就是说新任务运行栈中此时只有上下文的数据
(VOID)memcpy_s(childStack, sizeof(TaskContext), cloneStack, sizeof(TaskContext));
((TaskContext *)childStack)->R0 = 0;//R0寄存器的值变为0
if (sp != 0) {
((TaskContext *)childStack)->USP = TRUNCATE(sp, LOSCFG_STACK_POINT_ALIGN_SIZE);//确保指针对齐,设置新的栈指针
((TaskContext *)childStack)->ULR = 0;
}
}
kernel\liteos_a\security\cap\capability.c
VOID OsCopyCapability(LosProcessCB *from, LosProcessCB *to)
{
UINT32 intSave;
SCHEDULER_LOCK(intSave);
to->capability = from->capability;
SCHEDULER_UNLOCK(intSave);
}
kernel\liteos_a\kernel\extended\liteipc\hm_liteipc.c
LITE_OS_SEC_TEXT_INIT STATIC UINT32 LiteIpcPoolInit(ProcIpcInfo *ipcInfo)
{
ipcInfo->pool.uvaddr = NULL;
ipcInfo->pool.kvaddr = NULL;
ipcInfo->pool.poolSize = 0;
ipcInfo->ipcTaskID = INVAILD_ID;
//初始化链表
LOS_ListInit(&ipcInfo->ipcUsedNodelist);
return LOS_OK;
}
LITE_OS_SEC_TEXT_INIT STATIC ProcIpcInfo *LiteIpcPoolCreate(VOID)
{
//从内存池中申请ProcIpcInfo内存
ProcIpcInfo *ipcInfo = LOS_MemAlloc(m_aucSysMem1, sizeof(ProcIpcInfo));
if (ipcInfo == NULL) {
return NULL;
}
(VOID)memset_s(ipcInfo, sizeof(ProcIpcInfo), 0, sizeof(ProcIpcInfo));
(VOID)LiteIpcPoolInit(ipcInfo);
return ipcInfo;
}
LITE_OS_SEC_TEXT ProcIpcInfo *LiteIpcPoolReInit(const ProcIpcInfo *parent)
{
ProcIpcInfo *ipcInfo = LiteIpcPoolCreate();
if (ipcInfo == NULL) {
return NULL;
}
ipcInfo->pool.uvaddr = parent->pool.uvaddr;
ipcInfo->pool.kvaddr = NULL;
ipcInfo->pool.poolSize = 0;
ipcInfo->ipcTaskID = INVAILD_ID;
return ipcInfo;
}
kernel\liteos_a\kernel\base\mp\los_mp.c
VOID LOS_MpSchedule(UINT32 target)
{
//获取当前的cpu id
UINT32 cpuid = ArchCurrCpuid();
target &= ~(1U << cpuid);
HalIrqSendIpi(target, LOS_MP_IPI_SCHEDULE);
}
kernel\liteos_a\arch\arm\gic\gic_v3.c
STATIC VOID GicSgi(UINT32 irq, UINT32 cpuMask)
{
UINT16 tList;
UINT32 cpu = 0;
UINT64 val, cluster;
//循环遍历,检测哪些cpu核心需要触发中断
while (cpuMask && (cpu < LOSCFG_KERNEL_CORE_NUM)) {
if (cpuMask & (1U << cpu)) {
cluster = CPU_MAP_GET(cpu) & ~0xffUL;
tList = GicTargetList(&cpu, cpuMask, cluster);
/* Generates a Group 1 interrupt for the current security state */
val = ((MPIDR_AFF_LEVEL(cluster, 3) << 48) | /* 3: Serial number, 48: Register bit offset */
(MPIDR_AFF_LEVEL(cluster, 2) << 32) | /* 2: Serial number, 32: Register bit offset */
(MPIDR_AFF_LEVEL(cluster, 1) << 16) | /* 1: Serial number, 16: Register bit offset */
(irq << 24) | tList); /* 24: Register bit offset */
//触发中断
GiccSetSgi1r(val);
}
cpu++;
}
}
VOID HalIrqSendIpi(UINT32 target, UINT32 ipi)
{
GicSgi(ipi, target);
}
kernel\liteos_a\arch\arm\include\gic_v3.h
STATIC INLINE VOID GiccSetSgi1r(UINT64 val)
{
//通过内嵌汇编语言在arm处理器上触发一个软件生成的中断(SGI);通过向ICC_SGI1R_EL1寄存器上写入特定的值实现
__asm__ volatile("msr " ICC_SGI1R_EL1 ", %0" ::"r"(val));
ISB;//指令同步屏障
DSB;//数据同步屏障
}
kernel\liteos_a\kernel\base\sched\los_sched.c
VOID LOS_Schedule(VOID)
{
UINT32 intSave;
LosTaskCB *runTask = OsCurrTaskGet();
//OsSchedRunqueue根据cpu id获取的对应的调度队列
SchedRunqueue *rq = OsSchedRunqueue();
if (OS_INT_ACTIVE) {//中断正在进行
OsSchedRunqueuePendingSet();//将当前调度队列的schedFlag设置为INT_PEND_RESCH(阻止调度)
return;
}
//判断是否可抢占调度,如果不能调度,则将当前调度队列的schedFlag设置为INT_PEND_RESCH(阻止调度)
//根据rq->taskLockCnt == 0判断是否可抢占
if (!OsPreemptable()) {
return;
}
/*
* 任务中的触发器调度也将执行切片检查
* 如有必要,它将及时放弃时间片。
* 否则,没有其他副作用。
*/
SCHEDULER_LOCK(intSave);
/*
* 计时单位是Cycle,这是系统最小的计时单位。Cycle的时长由系统主时钟频率决定,系统主时钟频率就是每秒钟的Cycle * 数,对于216 MHz的CPU,1秒产生216000000个cycles。
* 获取当前时间cycle
* STATIC INLINE UINT64 OsGetCurrSchedTimeCycle(VOID)
* {
* return HalClockGetCycles();
* }
*/
//根据不同的调度算法,timeSliceUpdate分别对应的函数为 HPFTimeSliceUpdate, EDFTimeSliceUpdate, IdleTimeSliceUpdate
//更新任务调度开始的时间为当前时间
runTask->ops->timeSliceUpdate(rq, runTask, OsGetCurrSchedTimeCycle());
/* add run task back to ready queue */
//将运行的任务重新入队调度队列
runTask->ops->enqueue(rq, runTask);
/* reschedule to new thread */
//重新调度新的任务
OsSchedResched();
SCHEDULER_UNLOCK(intSave);
}
......
VOID OsSchedResched(VOID)
{
LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));
SchedRunqueue *rq = OsSchedRunqueue();
#ifdef LOSCFG_KERNEL_SMP
LOS_ASSERT(rq->taskLockCnt == 1);
#else
LOS_ASSERT(rq->taskLockCnt == 0);
#endif
rq->schedFlag &= ~INT_PEND_RESCH;
LosTaskCB *runTask = OsCurrTaskGet();
LosTaskCB *newTask = TopTaskGet(rq);
//如果当前运行的任务是调度队列栈顶的任务直接退出
if (runTask == newTask) {
return;
}
//如果当前运行的任务不是调度队列栈顶的任务,则切换新的栈顶任务运行
SchedTaskSwitch(rq, runTask, newTask);
}
......
STATIC INLINE VOID SchedSwitchCheck(LosTaskCB *runTask, LosTaskCB *newTask)
{
#ifdef LOSCFG_BASE_CORE_TSK_MONITOR
TaskStackCheck(runTask, newTask);
#endif /* LOSCFG_BASE_CORE_TSK_MONITOR */
OsHookCall(LOS_HOOK_TYPE_TASK_SWITCHEDIN, newTask, runTask);
}
STATIC VOID SchedTaskSwitch(SchedRunqueue *rq, LosTaskCB *runTask, LosTaskCB *newTask)
{
SchedSwitchCheck(runTask, newTask);
runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING;
newTask->taskStatus |= OS_TASK_STATUS_RUNNING;
#ifdef LOSCFG_KERNEL_SMP
/* mask new running task's owner processor */
runTask->currCpu = OS_TASK_INVALID_CPUID;
newTask->currCpu = ArchCurrCpuid();
#endif
OsCurrTaskSet((VOID *)newTask);
#ifdef LOSCFG_KERNEL_VM
if (newTask->archMmu != runTask->archMmu) {
//切换进程时,对应的切换mmu上下文
LOS_ArchMmuContextSwitch((LosArchMmu *)newTask->archMmu);
}
#endif
#ifdef LOSCFG_KERNEL_CPUP
//结束当前任务的cpu使用分析,开始新任务的cpu使用分析
OsCpupCycleEndStart(runTask, newTask);
#endif
#ifdef LOSCFG_SCHED_HPF_DEBUG
UINT64 waitStartTime = newTask->startTime;
#endif
if (runTask->taskStatus & OS_TASK_STATUS_READY) {
/* When a thread enters the ready queue, its slice of time is updated */
newTask->startTime = runTask->startTime;
} else {
/* The currently running task is blocked */
newTask->startTime = OsGetCurrSchedTimeCycle();
/* The task is in a blocking state and needs to update its time slice before pend */
runTask->ops->timeSliceUpdate(rq, runTask, newTask->startTime);
if (runTask->taskStatus & (OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY)) {
OsSchedTimeoutQueueAdd(runTask, runTask->ops->waitTimeGet(runTask));
}
}
UINT64 deadline = newTask->ops->deadlineGet(newTask);
SchedNextExpireTimeSet(newTask->taskID, deadline, runTask->taskID);
#ifdef LOSCFG_SCHED_HPF_DEBUG
newTask->schedStat.waitSchedTime += newTask->startTime - waitStartTime;
newTask->schedStat.waitSchedCount++;
runTask->schedStat.runTime = runTask->schedStat.allRuntime;
runTask->schedStat.switchCount++;
#endif
/* do the task context switch */
//切换任务上下文,OsTaskSchedule是一个汇编函数 见于 los_dispatch.s
OsTaskSchedule(newTask, runTask);
}
推荐阅读
-
红梦叉特色
-
探索二叉树、红黑树、递归树、堆和堆排序的数据结构与算法(第四部分),以及堆的实际应用
-
中文顶刊上用准自然实验识别的实证文章有哪些?有的附程序和code, 不看至少需要收藏一下!-经济研究 [1]刘啟仁,赵灿.税收政策激励与企业人力资本升级[J].经济研究,2020,55(04):70-85. [2]李广众,朱佳青,李杰,李新春.经理人相对绩效评价与企业并购行为:理论与实证[J].经济研究,2020,55(03):65-82. [3]张克中,欧阳洁,李文健.缘何“减税难降负”:信息技术、征税能力与企业逃税[J].经济研究,2020,55(03):116-132. [4]周波,赵国昌.中国间接税税负归宿研究:汽车市场准自然实验的证据[J].经济研究,2020,55(03):133-147. [5]毛其淋.贸易政策不确定性是否影响了中国企业进口?[J].经济研究,2020,55(02):148-164. [6]刘瑞明,毛宇,亢延锟.制度松绑、市场活力激发与旅游经济发展——来自中国文化*改革的证据[J].经济研究,2020,55(01):115-131. [7]施新政,高文静,陆瑶,李蒙蒙.资本市场配置效率与劳动收入份额——来自股权分置改革的证据[J].经济研究,2019,54(12):21-37. [8]王永钦,吴娴.中国创新型货币政策如何发挥作用:抵押品渠道[J].经济研究,2019,54(12):86-101. [9]唐宜红,俞峰,林发勤,张梦婷.中国高铁、贸易成本与企业出口研究[J].经济研究,2019,54(07):158-173. [10]张琦,郑瑶,孔东民.地区环境治理压力、高管经历与企业环保投资——一项基于《环境空气质量标准(2012)》的准自然实验[J].经济研究,2019,54(06):183-198. [11]冯晨,陈舒,白彩全.长期人力资本积累的历史根源:制度差异、儒家文化传播与国家能力塑造[J].经济研究,2019,54(05):146-163. [12]刘柏惠,寇恩惠,杨龙见.增值税多档税率、资源误置与全要素生产率损失[J].经济研究,2019,54(05):113-128. [13]陈林,万攀兵.《京都议定书》及其清洁发展机制的减排效应——基于中国参与全球环境治理微观项目数据的分析[J].经济研究,2019,54(03):55-71. [14]范子英,赵仁杰.法治强化能够促进污染治理吗?——来自环保法庭设立的证据[J].经济研究,2019,54(03):21-37. [15]夏怡然,陆铭.跨越世纪的城市人力资本足迹——历史遗产、政策冲击和劳动力流动[J].经济研究,2019,54(01):132-149. [16]毛其淋.人力资本推动中国加工贸易升级了吗?[J].经济研究,2019,54(01):52-67. [17]齐绍洲,林屾,崔静波.环境权益交易市场能否诱发绿色创新?——基于我国上市公司绿色专利数据的证据[J].经济研究,2018,53(12):129-143. [18]李明,李德刚,冯强.中国减税的经济效应评估——基于所得税分享改革“准自然试验”[J].经济研究,2018,53(07):121-135. [19]陈德球,陈运森.政策不确定性与上市公司盈余管理[J].经济研究,2018,53(06):97-111. [20]杜鹏程,徐舒,吴明琴.劳动保护与农民工福利改善——基于新《劳动合同法》的视角[J].经济研究,2018,53(03):64-78. [21]许和连,王海成.简政放权改革会改善企业出口绩效吗?——基于出口退(免)税审批权下放的准自然试验[J].经济研究,2018,53(03):157-170. [22]苏冬蔚,倪博.转融券制度、卖空约束与股价变动[J].经济研究,2018,53(03):110-125. [23]毕青苗,陈希路,徐现祥,李书娟.行政审批改革与企业进入[J].经济研究,2018,53(02):140-155. [24]李艳,杨汝岱.地方国企依赖、资源配置效率改善与供给侧改革[J].经济研究,2018,53(02):80-94. [25]陈林.自然垄断与混合所有制改革——基于自然实验与成本函数的分析[J].经济研究,2018,53(01):81-96. [26]赵西亮.教育、户籍转换与城乡教育收益率差异[J].经济研究,2017,52(12):164-178. [27]陆蓉,何婧,崔晓蕾.资本市场错误定价与产业结构调整[J].经济研究,2017,52(11):104-118. [28]*生,李好,马伟力,林秉旋.融资融券交易的信息治理效应[J].经济研究,2017,52(11):150-164. [29]钱雪松,方胜.担保物权制度改革影响了民营企业负债融资吗?——来自中国《物权法》自然实验的经验证据[J].经济研究,2017,52(05):146-160. [30]王朝阳,王振霞.涨跌停、融资融券与股价波动率——基于AH股的比较研究[J].经济研究,2017,52(04):151-165. [31]范子英,彭飞.“营改增”的减税效应和分工效应:基于产业互联的视角[J].经济研究,2017,52(02):82-95. [32]马述忠,张洪胜.集群商业信用与企业出口——对中国出口扩张奇迹的一种解释[J].经济研究,2017,52(01):13-27. [33]余明桂,钟慧洁,范蕊.业绩考核制度可以促进央企创新吗?[J].经济研究,2016,51(12):104-117. [34]林卉,许尤洋,刘峰.中国资本市场“框架效应”现象的实证研究——基于中组部18号文的自然实验[J].经济研究,2016,51(12):161-175. [35]刘啟仁,黄建忠.人民币汇率、依市场定价与资源配置效率[J].经济研究,2016,51(12):18-31. [36]叶青,赵良玉,刘思辰.独立董事“政商旋转门”之考察:一项基于自然实验的研究[J].经济研究,2016,51(06):98-113. [37]范子英,彭飞,刘冲.政治关联与经济增长——基于卫星灯光数据的研究[J].经济研究,2016,51(01):114-126. [38]毛其淋,许家云.中间品贸易*化与制造业就业变动——来自中国加入WTO的微观证据[J].经济研究,2016,51(01):69-83. [39]赵绍阳,臧文斌,尹庆双.医疗保障水平的福利效果[J].经济研究,2015,50(08):130-145. [40]*生,陈晨,林秉旋.卖空机制提高了中国股票市场的定价效率吗?——基于自然实验的证据[J].经济研究,2015,50(04):165-177. [41]李科,徐龙炳,朱伟骅.卖空限制与股票错误定价——融资融券制度的证据[J].经济研究,2014,49(10):165-178. [42]简泽,张涛,伏玉林.进口*化、竞争与本土企业的全要素生产率——基于中国加入WTO的一个自然实验[J].经济研究,2014,49(08):120-132. [43]范子英,李欣.部长的政治关联效应与财政转移支付分配[J].经济研究,2014,49(06):129-141. [44]陈刚,李树.司法独立与市场分割——以法官异地交流为实验的研究[J].经济研究,2013,48(09):30-42+70. [45]范子英,田彬彬.税收竞争、税收执法与企业避税[J].经济研究,2013,48(09):99-111. [46]简泽,干春晖,余典范.银行部门的市场化、信贷配置与工业重构[J].经济研究,2013,48(05):112-127. [47]李树,陈刚.环境管制与生产率增长——以APPCL2000的修订为例[J].经济研究,2013,48(01):17-31. [48]马双,张劼,朱喜.最低工资对中国就业和工资水平的影响[J].经济研究,2012,47(05):132-146. [49]白重恩,李宏彬,吴斌珍.医疗保险与消费:来自新型农村合作医疗的证据[J].经济研究,2012,47(02):41-53. [50]叶光亮,邓国营,黎志刚.个人住房贷款行为与房贷调控的有效性分析[J].经济研究,2011,46(S1):105-115. 经济学季刊 [1]王剑程,李丁,马双.宽带建设对农户创业的影响研究——基于“宽带乡村”建设的准自然实验[J].经济学(季刊),2020,19(01):209-232. [2]李仲飞,于守金,曹夏平.产业信贷政策对于房地产企业债务的影响——基于银行业359号“限贷”文件的准自然实验分析[J].经济学(季刊),2019,18(04):1373-1396. [3]吕铁,王海成.放松银行准入管制与企业创新——来自股份制商业银行在县域设立分支机构的准自然试验[J].经济学(季刊),2019,18(04):1443-1464. [4]陈晓红,朱蕾,汪阳洁.驻地效应——来自国家土地督察的经验证据[J].经济学(季刊),2019,18(01):99-122. [5]刘行,叶康涛,陆正飞.加速折旧政策与企业投资——基于“准自然实验”的经验证据[J].经济学(季刊),2019,18(01):213-234. [6]毛其淋,许家云.外资进入如何影响了本土企业出口国内附加值?[J].经济学(季刊),2018,17(04):1453-1488. [7]王智波,韩希.废止收容遣送制度的经济影响——基于检验最优城市理论的实证研究[J].经济学(季刊),2018,17(03):1013-1034. [8]卢盛峰,吴一平,谢潇.历史名片的经济价值——来自中国城市更名的证据[J].经济学(季刊),2018,17(03):1055-1078. [9]郭峰,熊瑞祥.地方金融机构与地区经济增长——来自城商行设立的准自然实验[J].经济学(季刊),2018,17(01):221-246. [10]*,李培鑫,李丽霞.*合作、市场整合与城市群经济绩效——基于长三角城市经济协调会的实证检验[J].经济学(季刊),2017,16(04):1563-1582. [11]边文龙,王向楠,李冉.保险费率市场化效果的解释和评估[J].经济学(季刊),2017,16(04):1477-1498. [12]刘怡,耿纯,赵仲匡.出口退税*间分担对产品出口的影响[J].经济学(季刊),2017,16(03):1011-1030. [13]倪骁然,朱玉杰.卖空压力影响企业的风险行为吗?——来自A股市场的经验证据[J].经济学(季刊),2017,16(03):1173-1198. [14]毛其淋,许家云.中间品贸易*化提高了企业加成率吗?——来自中国的证据[J].经济学(季刊),2017,16(02):485-524. [15]刘瑞明,赵仁杰.匿名审稿制度推动了中国的经济学进步吗?——基于双重差分方法的研究[J].经济学(季刊),2017,16(01):173-204. [16]范子英,田彬彬.政企合谋与企业逃税:来自国税局长异地交流的证据[J].经济学(季刊),2016,15(04):1303-1328. [17]丘心颖,郑小翠,邓可斌.分析师能有效发挥专业解读信息的作用吗?——基于汉字年报复杂性指标的研究[J].经济学(季刊),2016,15(04):1483-1506. [18]马榕,石晓军.中国债券信用评级结果具有甄别能力吗?——基于盈余管理敏感性的视角[J].经济学(季刊),2016,15(01):197-216. [19]李楠,林矗.太平天国战争对近代人口影响的再估计——基于历史自然实验的实证分析[J].经济学(季刊),2015,14(04):1325-1346. [20]管汉晖,陈博凯.货币的非国家化:汉代中国的经历(前175—前144年)[J].经济学(季刊),2015,14(04):1497-1518. [21]陈思霞,卢盛峰.分权增加了民生性财政支出吗?——来自中国“省直管县”的自然实验[J].经济学(季刊),2014,13(04):1261-1282. [22]马双,孟宪芮,甘犁.养老保险企业缴费对员工工资、就业的影响分析[J].经济学(季刊),2014,13(03):969-1000. [23]马双,甘犁.最低工资对企业在职培训的影响分析[J].经济学(季刊),2014,13(01):1-26. [24]何浩然.公共政策的效果能否被准确预测?来自中国塑料袋使用限制政策的自然实验证据[J].经济学(季刊),2012,11(04):1305-1322. [25]雷晓燕.管理医疗模式的影响差异——来自加州医疗救助的经验证据[J].经济学(季刊),2010,9(01):333-348. 管理世界 [1]李永友,王超.集权式财政改革能够缩小城乡差距吗?——基于“乡财县管”准自然实验的证据[J].管理世界,2020,36(04):113-130. [2]肖静华,胡杨颂,吴瑶.成长品:数据驱动的企业与用户互动创新案例研究[J].管理世界,2020,36(03):183-205. [3]贾建民,耿维,徐戈,郝辽钢,贾轼.大数据行为研究趋势:一个“时空关”的视角[J].管理世界,2020,36(02):106-116+211-212. [4]黄俊威,龚光明.融资融券制度与公司资本结构动态调整——基于“准自然实验”的经验证据[J].管理世界,2019,35(10):64-81. [5]陈林,万攀兵,许莹盈.混合所有制企业的股权结构与创新行为——基于自然实验与断点回归的实证检验[J].管理世界,2019,35(10):186-205. [6]刘冲,刘晨冉,孙腾.交通基础设施、金融约束与县域产业发展——基于“国道主干线系统”自然实验的证据[J].管理世界,2019,35(07):78-88+203. [7]周茂,李雨浓,姚星,陆毅.人力资本扩张与中国城市制造业出口升级:来自高校扩招的证据[J].管理世界,2019,35(05):64-77+198-199. [8]陈胜蓝,马慧.贷款可获得性与公司商业信用——中国利率市场化改革的准自然实验证据[J].管理世界,2018,34(11):108-120+149. [9]毛其淋,许家云.贸易政策不确定性与企业储蓄行为——基于中国加入WTO的准自然实验[J].管理世界,2018,34(05):10-27+62+179. [10]赵静,*昌,刘峰.高铁开通与股价崩盘风险[J].管理世界,2018,34(01):157-168+192. [11]钟覃琳,陆正飞.资本市场开放能提高股价信息含量吗?——基于“沪港通”效应的实证检验[J].管理世界,2018,34(01):169-179. [12]叶菁菁,吴燕,陈方豪,王宇晴.个人所得税减免会增加劳动供给吗?——来自准自然实验的证据[J].管理世界,2017(12):20-32+187. [13]谢贞发,严瑾,李培.中国式“压力型”财政激励的财源增长效应——基于取消农业税改革的实证研究[J].管理世界,2017(12):46-60+187-188. [14]刘行,赵健宇,叶康涛.企业避税、债务融资与债务融资来源——基于所得税征管*改革的断点回归分析[J].管理世界,2017(10):113-129. [15]李超,李涵.空气污染对企业库存的影响——基于我国制造业企业数据的实证研究[J].管理世界,2017(08):95-105. [16]李文贵,余明桂,钟慧洁.央企董事会试点、国有上市公司代理成本与企业绩效[J].管理世界,2017(08):123-135+153. [17]陈胜蓝,马慧.卖空压力与公司并购——来自卖空管制放松的准自然实验证据[J].管理世界,2017(07):142-156. [18]申广军,邹静娴.企业规模、政企关系与实际税率——来自世界银行“投资环境调查”的证据[J].管理世界,2017(06):23-36. [19]卢盛峰,陈思霞.*偏袒缓解了企业融资约束吗?——来自中国的准自然实验[J].管理世界,2017(05):51-65+187-188. [20]顾乃康,周艳利.卖空的事前威慑、公司治理与企业融资行为——基于融资融券制度的准自然实验检验[J].管理世界,2017(02):120-134. [21]权小锋,尹洪英.中国式卖空机制与公司创新——基于融资融券分步扩容的自然实验[J].管理世界,2017(01):128-144+187-188. [22]倪骁然,朱玉杰.劳动保护、劳动密集度与企业创新——来自2008年《劳动合同法》实施的证据[J].管理世界,2016(07):154-167. [23]许伟,陈斌开.税收激励和企业投资——基于2004~2009年增值税转型的自然实验[J].管理世界,2016(05):9-17. [24]范子英,刘甲炎.为买房而储蓄——兼论房产税改革的收入分配效应[J].管理世界,2015(05):18-27+187. [25]李涵,唐丽淼.交通基础设施投资、空间溢出效应与企业库存[J].管理世界,2015(04):126-136. [26]贾俊雪,宁静.纵向财政治理结构与地方*职能优化——基于省直管县财政*改革的拟自然实验分析[J].管理世界,2015(01):7-17+187. [27]余淼杰,梁中华.贸易*化与中国劳动收入份额——基于制造业贸易企业数据的实证分析[J].管理世界,2014(07):22-31. [28]刘行,叶康涛.金融发展、产权与企业税负[J].管理世界,2014(03):41-52. [29]李泽广,马泽昊.契约环境、代理成本与企业投资—债务期限关系[J].管理世界,2013(08):183-185. [30]叶青,李增泉,李光青.富豪榜会影响企业会计信息质量吗?——基于政治成本视角的考察[J].管理世界,2012(01):104-120. [31]郑新业,王晗,赵益卓.“省直管县”能促进经济增长吗?——双重差分方法[J].管理世界,2011(08):34-44+65. [32]王贤彬,聂海峰.行政区划调整与经济增长[J].管理世界,2010(04):42-53. [33]贾明,张喆.高管的政治关联影响公司慈善行为吗?[J].管理世界,2010(04):99-113+187. [34]聂辉华,方明月,李涛.增值税转型对企业行为和绩效的影响——以东北地区为例[J].管理世界,2009(05):17-24+35. [35]攀登,施东晖,宋铮.证券市场泡沫的生成机理分析——基于宝钢权证自然实验的实证研究[J].管理世界,2008(04):15-23+186. 世界经济 [1]吉赟,杨青.高铁开通能否促进企业创新:基于准自然实验的研究[J].世界经济,2020,43(02):147-166. [2]毛其淋,方森辉.外资进入*化如何影响中国制造业生产率[J].世界经济,2020,43(01):143-169. [3]刘灿雷,王永进.出口扩张与企业间工资差距:影响与机制[J].世界经济,2019,42(12):99-120. [4]林志帆,龙晓旋.卖空威胁能否激励中国企业创新[J].世界经济,2019,42(09):126-150. [5]李嘉楠,代谦,庄嘉霖.开放、市场整合与经济空间变迁:基于近代中国开埠的证据[J].世界经济,2019,42(09):27-51. [6]李磊,王小霞,蒋殿春,方森辉.中国最低工资上升是否导致了外资撤离[J].世界经济,2019,42(08):97-120. [7]郭俊杰,方颖,杨阳.排污费征收标准改革是否促进了中国工业二氧化硫减排[J].世界经济,2019,42(01):121-144. [8]蒋灵多,陆毅,陈勇兵.市场机制是否有利于僵尸企业处置:以外资管制放松为例[J].世界经济,2018,41(09):121-145. [9]施震凯,邵军,浦正宁.交通基础设施改善与生产率增长:来自铁路大提速的证据[J].世界经济,2018,41(06):127-151. [10]李胜旗,毛其淋.关税政策不确定性如何影响就业与工资[J].世界经济,2018,41(06):28-52. [11]曾建光,步丹璐,饶品贵.无偿划转、*补贴与社会福利[J].世界经济,2017,40(07):147-168. [12]马双,邱光前.最低工资对中国劳动密集型出口产品价格的影响[J].世界经济,2016,39(11):80-103. [13]周茂,陆毅,符大海.贸易*化与中国产业升级:事实与机制[J].世界经济,2016,39(10):78-102. [14]彭飞,范子英.税收优惠、捐赠成本与企业捐赠[J].世界经济,2016,39(07):144-167. [15]代谦,别朝霞.财政压力的经济后果:以宋朝的“靖康之变”为例[J].世界经济,2015,38(01):173-192. [16]戴觅,茅锐.外需冲击、企业出口与内销:金融危机时期的经验证据[J].世界经济,2015,38(01):81-104. [17]田巍,余淼杰.中间品贸易*化和企业研发:基于中国数据的经验分析[J].世界经济,2014,37(06):90-112. [18]刘甲炎,范子英.中国房产税试点的效果评估:基于合成控制法的研究[J].世界经济,2013,36(11):117-135. [19]王永进,盛丹.经济波动、劳动力市场摩擦与产业结构[J].世界经济,2013,36(04):22-46. [20]何浩然,陈叶烽.禀赋获得方式影响被试行为是否存在性别差异:来自自然现场实验的证据[J].世界经济,2012,35(04):102-117. [21]周浩,郑筱婷.交通基础设施质量与经济增长:来自中国铁路提速的证据[J].世界经济,2012,35(01):78-97. [22]冯皓,陆铭.通过买房而择校:教育影响房价的经验证据与政策含义[J].世界经济,2010,33(12):89-104. [23]曾海舰,苏冬蔚.信贷政策与公司资本结构[J].世界经济,2010,33(08):17-42. 金融研究 [1]吕朝凤,毛霞.地方金融发展能够影响FDI的区位选择吗?——一个基于城市商业银行设立的准自然实验[J].金融研究,2020(03):58-76. [2]许红梅,李春涛.劳动保护、社保压力与企业违约风险——基于《社会保险法》实施的研究[J].金融研究,2020(03):115-133. [3]胡珺,黄楠,沈洪涛.市场激励型环境规制可以推动企业技术创新吗?——基于中国碳排放权交易机制的自然实验[J].金融研究,2020(01):171-189. [4]诸竹君,黄先海,王煌.交通基础设施改善促进了企业创新吗?——基于高铁开通的准自然实验[J].金融研究,2019(11):153-169. [5]鲁元平,赵颖,石智雷.产假政策与子女长期人力资本积累[J].金融研究,2019(11):57-74. [6]刘杰,陈佳,刘力.投资者关注与市场反应——来自中国证券交易所交易公开信息的自然实验[J].金融研究,2019(11):189-206. [7]陈胜蓝,刘晓玲.中国城际高铁与商业信用供给——基于准自然实验的研究[J].金融研究,2019(10):117-134. [8]张*,王永进,李坤望.贸易*化对制造业企业现金储蓄的影响——预防性动机还是投资挤压?[J].金融研究,2019(09):19-38. [9]段白鸽,王永钦,夏梦嘉.金融创新如何缓解信任品市场失灵?——中国食品安全责任强制保险的自然实验[J].金融研究,2019(09):75-93. [10]陈运森,黄健峤.股票市场开放与企业投资效率——基于“沪港通”的准自然实验[J].金融研究,2019(08):151-170. [11]钱雪松,唐英伦,方胜.担保物权制度改革降低了企业债务融资成本吗?——来自中国《物权法》自然实验的经验证据[J].金融研究,2019(07):115-134. [12]卞元超,吴利华,白俊红.高铁开通是否促进了区域创新?[J].金融研究,2019(06):132-149. [13]杨筝,王红建,戴静,许传华.放松利率管制、利润率均等化与实体企业“脱实向虚”[J].金融研究,2019(06):20-38. [14]张鹏杨,徐佳君,刘会政.产业政策促进全球价值链升级的有效性研究——基于出口加工区的准自然实验[J].金融研究,2019(05):76-95. [15]杨青,吉赟,王亚男.高铁能提升分析师盈余预测的准确度吗?——来自上市公司的证据[J].金融研究,2019(03):168-188. [16]李建军,韩珣.普惠金融、收入分配和贫困减缓——推进效率和公平的政策框架选择[J].金融研究,2019(03):129-148. [17]李广众,贾凡胜.*财政激励、税收征管动机与企业盈余管理——以财政“省直管县”改革为自然实验的研究[J].金融研究,2019(02):78-97. [18]王永钦,徐鸿恂.杠杆率如何影响资产价格?——来自中国债券市场自然实验的证据[J].金融研究,2019(02):20-39. [19]毛其淋.外资进入*化如何影响了中国本土企业创新?[J].金融研究,2019(01):72-90. [20]苏冬蔚,连莉莉.绿色信贷是否影响重污染企业的投融资行为?[J].金融研究,2018(12):123-137. [21]郑志刚,刘思敏,黄继承.我国上市公司策略性股票更名:战略转型还是高位*?[J].金融研究,2018(10):158-173. [22]陈康,刘琦.股价信息含量与投资-股价敏感性——基于融资融券的准自然实验[J].金融研究,2018(09):126-142. [23]朱莹,王健.市场约束能够降低地方债风险溢价吗?——来自城投债市场的证据[J].金融研究,2018(06):56-72. [24]王永钦,陈映辉,熊雅文.存款保险制度如何影响公众对不同银行的信心?——来自中国的证据[J].金融研究,2018(06):109-122. [25]王芳,陈硕,王瑾.农业税减免、农业发展与地方*行为——县级证据[J].金融研究,2018(04):104-120. [26]叶康涛,刘芳,李帆.股指成份股调整与股价崩盘风险:基于一项准自然实验的证据[J].金融研究,2018(03):172-189. [27]王红建,杨筝,阮刚铭,曹瑜强.放松利率管制、过度负债与债务期限结构[J].金融研究,2018(02):100-117. [28]姜军,申丹琳,江轩宇,伊志宏.债权人保护与企业创新[J].金融研究,2017(11):128-142. [29]王攀娜,罗宏.放松卖空管制对分析师预测行为的影响——来自中国准自然实验的证据[J].金融研究,2017(11):191-206. [30]李春涛,刘贝贝,周鹏.卖空与信息披露:融券准自然实验的证据[J].金融研究,2017(09):130-145. [31]胡婷,惠凯,彭红枫.异常波动停牌对股价波动性和流动性的影响研究——来自我国取消异常波动停牌的自然实验[J].金融研究,2017(09):146-160. [32]杨晓兰,金雪军.我国股票市场熔断机制的磁力效应:基于自然实验的证据[J].金融研究,2017(09):161-177. [33]曹春方,陈露兰,张婷婷.“法律的名义”:司法独立性提升与公司违规[J].金融研究,2017(05):191-206. [34]杨筝,刘放,李茫茫.利率市场化、非效率投资与资本配置——基于中国人民银行取消贷款利率上下限的自然实验[J].金融研究,2017(05):81-96. [35]王兵,戴敏,武文杰.环保基地政策提高了企业环境绩效吗?——来自东莞市企业微观面板数据的证据[J].金融研究,2017(04):143-160. [36]冯根福,刘虹,冯照桢,温军.股票流动性会促进我国企业技术创新吗?[J].金融研究,2017(03):192-206. [37]侯青川,靳庆鲁,刘阳.放松卖空管制与公司现金价值——基于中国资本市场的准自然实验[J].金融研究,2016(11):112-127. [38]张三峰,张伟.融资约束、金融发展与企业雇佣——来自中国企业调查数据的经验证据[J].金融研究,2016(10):111-126. [39]王茂斌,孔东民.反腐败与中国公司治理优化:一个准自然实验[J].金融研究,2016(08):159-174. [40]卢盛峰,陈思霞.政策偏袒的经济收益:来自中国工业企业出口的证据[J].金融研究,2016(07):33-47. [41]张龙耀,杨骏,程恩江.融资杠杆监管与小额贷款公司“覆盖率-可持续性”权衡——基于分层监管的准自然实验[J].金融研究,2016(06):142-158. [42]陈海强,韩乾,吴锴.融资约束抑制技术效率提升吗?——基于制造业微观数据的实证研究[J].金融研究,2015(10):148-162. [43]*生,杜爽,林秉旋.卖空交易与股票价格稳定性——来自中国融资融券市场的自然实验[J].金融研究,2015(06):173-188. [44]汪小圈,张红,刘冲.幼年饥荒经历对个人自雇选择的影响[J].金融研究,2015(05):18-33. [45]曾建光,伍利娜,王立彦,諶家蘭.技术进步、信息透明度与开放式基金的资金流量——基于中国开放式基金强制采用XBRL的证据[J].金融研究,2014(08):131-145. [46]马光荣,刘明,杨恩艳.银行授信、信贷紧缩与企业研发[J].金融研究,2014(07):76-93. [47]梁中华,余淼杰.人民币升值与中国出口企业盈利能力——基于面板数据的实证分析[J].金融研究,2014(07):1-15. [48]简泽.银行债权治理、管理者偏好与国有企业的绩效[J].金融研究,2013(01):135-148. [49]余静文.信贷约束、股利分红与企业预防性储蓄动机——来自中国A股上市公司的证据[J].金融研究,2012(10):97-110. 统计研究 [1]王亚飞,廖甍,王亚菲.高铁开通促进了农业全要素生产率增长吗?——来自长三角地区准自然实验的经验证据[J].统计研究,2020,37(05):40-53. [2]胡宗义,李毅.环境信息披露的污染减排效应评估[J].统计研究,2020,37(04):59-74. [3]严文龙,陈宋生,田至立.审计定价管制与交易剩余——2010年审计定价管制失效的自然实验[J/OL].统计研究:1-11[2020-06-05].http://kns.cnki.net/kcms/detail/11.1302.C.20200325.1534.002.html. [4]王立勇,许明.中国精准扶贫政策的减贫效应研究:来自准自然实验的经验证据[J].统计研究,2019,36(12):15-26. [5]许家云.互联网如何影响工业结构升级?——基于互联网商用的自然实验[J].统计研究,2019,36(12):55-67. [6]邹伟,梁平汉.腾飞的翅膀:机场属地化改革与企业库存[J].统计研究,2019,36(11):76-89. [7]徐超,庞保庆,张充.降低实体税负能否遏制制造业企业“脱实向虚”[J].统计研究,2019,36(06):42-53. [8]卢盛峰,陈思霞,张东杰.*推动型城市化促进了县域经济发展吗[J].统计研究,2017,34(05):59-68. [9]许坤,苏扬.逆周期资本监管、监管压力与银行信贷研究[J].统计研究,2016,33(03):97-105. 中国工业经济 [1]谭小芬,钱佳琪.资本市场压力与企业策略性专利行为:卖空机制的视角[J].中国工业经济,2020(05):156-173. [2]于新亮,上官熠文,于文广,李倩.养老保险缴费率、资本——技能互补与企业全要素生产率[J].中国工业经济,2019(12):96-114. [3]饶品贵,王得力,李晓溪.高铁开通与供应商分布决策[J].中国工业经济,2019(10):137-154. [4]王雄元,卜落凡.国际出口贸易与企业创新——基于“中欧班列”开通的准自然实验研究[J].中国工业经济,2019(10):80-98. [5]黄溶冰,赵谦,王丽艳.自然资源资产离任审计与空气污染防治:“和谐锦标赛”还是“环保资格赛”[J].中国工业经济,2019(10):23-41. [6]张国建,佟孟华,李慧,陈飞.扶贫改革试验区的经济增长效应及政策有效性评估[J].中国工业经济,2019(08):136-154. [7]孟庆斌,李昕宇,张修平.卖空机制、资本市场压力与公司战略选择[J].中国工业经济,2019(08):155-173. [8]徐思,何晓怡,钟凯.“一带一路”倡议与中国企业融资约束[J].中国工业经济,2019(07):155-173. [9]任胜钢,郑晶晶,刘东华,陈晓红.排污权交易机制是否提高了企业全要素生产率——来自中国上市公司的证据[J].中国工业经济,2019(05):5-23. [10]宋贺,段军山.财务顾问与企业并购绩效[J].中国工业经济,2019(05):155-173. [11]史贝贝,冯晨,康蓉.环境信息披露与外商直接投资结构优化[J].中国工业经济,2019(04):98-116. [12]王桂军,卢潇潇.“一带一路”倡议与中国企业升级[J].中国工业经济,2019(03):43-61. [13]魏悦羚,张洪胜.进口*化会提升中国出口国内增加值率吗——基于总出口核算框架的重新估计[J].中国工业经济,2019(03):24-42. [14]孙雪娇,翟淑萍,于苏.柔性税收征管能否缓解企业融资约束——来自纳税信用评级披露自然实验的证据[J].中国工业经济,2019(03):81-99. [15]吴晓晖,郭晓冬,乔政.机构投资者抱团与股价崩盘风险[J].中国工业经济,2019(02):117-135. [16]贾俊雪,李紫霄,秦聪.社会保障与经济增长:基于拟自然实验的分析[J].中国工业经济,2018(11):42-60. [17]刘友金,曾小明.房产税对产业转移的影响:来自重庆和上海的经验证据[J].中国工业经济,2018(11):98-116. [18]蒋灵多,陆毅.市场竞争加剧是否助推国有企业加杠杆[J].中国工业经济,2018(11):155-173. [19]钱雪松,康瑾,唐英伦,曹夏平.产业政策、资本配置效率与企业全要素生产率——基于中国2009年十大产业振兴规划自然实验的经验研究[J].中国工业经济,2018(08):42-59. [20]诸竹君,黄先海,余骁.进口中间品质量、自主创新与企业出口国内增加值率[J].中国工业经济,2018(08):116-134. [21]李蕾蕾,盛丹.地方环境立法与中国制造业的行业资源配置效率优化[J].中国工业经济,2018(07):136-154. [22]李贲,吴利华.开发区设立与企业成长:异质性与机制研究[J].中国工业经济,2018(04):79-97. [23]龙小宁,林菡馨.专利执行保险的创新激励效应[J].中国工业经济,2018(03):116-135. [24]周茂,陆毅,杜艳,姚星.开发区设立与地区制造业升级[J].中国工业经济,2018(03):62-79. [25]余静文.企业国有化中的*角色[J].中国工业经济,2018(03):155-173. [26]刘瑞明,李林,亢延锟,赵勇.景点评选、*公共服务供给与地区旅游经济发展[J].中国工业经济,2018(02):118-136. [27]王永进,冯笑.行政审批制度改革与企业创新[J].中国工业经济,2018(02):24-42. [28]史贝贝,冯晨,张妍,杨菲.环境规制红利的边际递增效应[J].中国工业经济,2017(12):40-58. [29]蒋灵多,陆毅.最低工资标准能否抑制新僵尸企业的形成[J].中国工业经济,2017(11):118-136. [30]张小茜,孙璐佳.抵押品清单扩大、过度杠杆化与企业破产风险——动产抵押法律改革的“双刃剑”效应[J].中国工业经济,2017(07):175-192. [31]龙小宁,万威.环境规制、企业利润率与合规成本规模异质性[J].中国工业经济,2017(06):155-174. [32]简泽,谭利萍,吕大国,符通.市场竞争的创造性、破坏性与技术升级[J].中国工业经济,2017(05):16-34. [33]王兵,聂欣.产业集聚与环境治理:助力还是阻力——来自开发区设立准自然实验的证据[J].中国工业经济,2016(12):75-89. [34]林乐,郑登津.退市监管与股价崩盘风险[J].中国工业经济,2016(12):58-74. [35]何靖.延付高管薪酬对银行风险承担的政策效应——基于银行盈余管理动机视角的PSM-DID分析[J].中国工业经济,2016(11):126-143. [36]龙小宁,张训常,杨进.转轨背景下官员兼职规制的经济效应[J].中国工业经济,2016(07):40-56. [37]罗知,赵奇伟,严兵.约束机制和激励机制对国有企业长期投资的影响[J].中国工业经济,2015(10):69-84. [38]赵晶,张书博,祝丽敏.传承人合法性对家族企业战略变革的影响[J].中国工业经济,2015(08):130-144. [39]吴海民,吴淑娟,陈辉.城市文明、交易成本与企业“第四利润源”——基于全国文明城市与民营上市公司核匹配倍差法的证据[J].中国工业经济,2015(07):114-129. [40]范子英.土地财政的根源:财政压力还是投资冲动[J].中国工业经济,2015(06):18-31. [41]韩超,胡浩然.清洁生产标准规制如何动态影响全要素生产率——剔除其他政策干扰的准自然实验分析[J].中国工业经济,2015(05):70-82. [42]唐明哲,刘丰波,林平.价格检验在相关市场界定中的实证运用——对茅台、五粮液垄断案的再思考[J].中国工业经济,2015(04):135-148. 会计研究 [1]朱焱,王玉丹.卖空机制与企业社会责任承担——基于中国融资融券制度的准自然实验研究[J].会计研究,2019(12):58-64. [2]刘行,赵健宇.税收激励与企业创新——基于增值税转型改革的“准自然实验”[J].会计研究,2019(09):43-49. [3]崔学刚,邓衢,邝文俊.卖空交易、市场行情与股价崩盘风险[J].会计研究,2019(06):43-50. [4]张金丹,路军,李连华.审计报告中披露关键审计事项信息有助于提高审计质量吗?——报表盈余和市场感知双维度的经验证据[J].会计研究,2019(06):85-91. [5]陈运森,黄健峤,韩慧云.股票市场开放提高现金股利水平了吗?——基于“沪港通”的准自然实验[J].会计研究,2019(03):55-62. [6]钱雪松,代禹斌,陈琳琳,方胜.担保物权制度改革、融资约束与企业现金持有——基于中国《物权法》自然实验的经验证据[J].会计研究,2019(01):72-78. [7]王仲兵,王攀娜.放松卖空管制与企业投资效率——来自中国资本市场的经验证据[J].会计研究,2018(09):80-87. [8]郝颖,谢光华,石锐.外部监管、在职消费与企业绩效[J].会计研究,2018(08):42-48. [9]吴战篪,陈相伊,吴伟立.融资融券制度与资产增长效应[J].会计研究,2017(06):89-95+97. [10]李丹,袁淳,廖冠民.卖空机制与分析师乐观性偏差——基于双重差分模型的检验[J].会计研究,2016(09):25-31. [11]刘运国,刘梦宁.雾霾影响了重污染企业的盈余管理吗?——基于政治成本假说的考察[J].会计研究,2015(03):26-33+94. [12]王春飞,陆正飞.事务所“改制”、保险价值与投资者保护[J].会计研究,2014(05):81-87+95. [13]陈运森,郑登津,李路.民营企业发审委社会关系、IPO资格与上市后表现[J].会计研究,2014(02):12-19+94. [14]曾建光,伍利娜,谌家兰,王立彦.XBRL、代理成本与绩效水平——基于中国开放式基金市场的证据[J].会计研究,2013(11):88-94+96. 世界经济文汇 [1]蓝嘉俊,方颖,魏下海.性别比失衡下的婚姻匹配与劳动力市场表现——基于独生子女政策准自然实验的实证分析[J].世界经济文汇,2019(04):67-84. [2]赵琳,唐珏,陈诗一.环保管理*垂直化改革的环境治理效应[J].世界经济文汇,2019(02):100-120. [3]周梦天,王之.空气质量信息公开会影响城市房价吗?——基于我国各城市公开PM2.5监测数据的自然实验[J].世界经济文汇,2018(03):20-42. [4]傅家范,刘冲.*注资、存款优势与国有银行反危机信贷投放[J].世界经济文汇,2017(05):75-90. [5]刘金山,*.对口支援政策有效吗?——来自19省市对口援疆自然实验的证据[J].世界经济文汇,2017(04):43-61. [6]陈怡安.父母政治身份、职位背景与子女创业[J].世界经济文汇,2017(01):26-50. [7]范子英.为买房而离婚——基于住房限购政策的研究[J].世界经济文汇,2016(04):1-17. 中国人口、资源与环境 [1]王为东,王冬,卢娜.中国碳排放权交易促进低碳技术创新机制的研究[J].中国人口·资源与环境,2020,30(02):41-48. [2]胡江峰,黄庆华,潘欣欣.碳排放交易制度与企业创新质量:抑制还是促进[J].中国人口·资源与环境,2020,30(02):49-59. [3]张晖,吴霜,张燕媛,虞祎.流域生态补偿政策对受偿地区经济增长的影响研究——以安徽省黄山市为例[J].长江流域资源与环境,2019,28(12):2848-2856. [4]刘常建,许为宾,蔡兰,张孝静.环保压力与重污染企业的银行贷款契约——基于“PM_(2.5)爆表”事件的经验证据[J].中国人口·资源与环境,2019,29(12):121-130. [5]龚梦琪,刘海云,姜旭.中国低碳试点政策对外商直接投资的影响研究[J].中国人口·资源与环境,2019,29(06):50-57. [6]尤济红,陈喜强.区域一体化合作是否导致污染转移——来自长三角城市群扩容的证据[J].中国人口·资源与环境,2019,29(06):118-129. [7]翟华云,刘亚伟.环境司法专门化促进了企业环境治理吗?——来自专门环境法庭设置的准自然实验[J].中国人口·资源与环境,2019,29(06):138-147. [8]张楠,卢洪友,黄健.资源枯竭城市转移支付对经济增长的影响[J].中国人口·资源与环境,2019,29(04):147-156. [9]赵领娣,徐乐.基于长三角扩容准自然实验的区域一体化水污染效应研究[J].中国人口·资源与环境,2019,29(03):50-61. [10]温湖炜,周凤秀.环境规制与中国省域绿色全要素生产率——兼论对《环境保护税法》实施的启示[J].干旱区资源与环境,2019,33(02):9-15. [11]景守武,张捷.新安江流域横向生态补偿降低水污染强度了吗?[J].中国人口·资源与环境,2018,28(10):152-159. [12]黄志平.碳排放权交易有利于碳减排吗?——基于双重差分法的研究[J].干旱区资源与环境,2018,32(09):32-36. [13]雷平,曹黎明,赵连荣.乡土官员对区域经济与环境发展路径的影响[J].中国人口·资源与环境,2018,28(04):163-176. [14]何文剑,徐静文,张红霄.森林采伐限额管理制度能否起到保护森林资源的作用[J].中国人口·资源与环境,2016,26(07):128-136. [15]何浩然,陈安来.中国限制塑料袋使用的政策效果及国际经验借鉴[J].中国人口·资源与环境,2010,20(11):167-174. 中国农村经济 [1]罗斯炫,何可,张俊飚.增产加剧污染?——基于粮食主产区政策的经验研究[J].中国农村经济,2020(01):108-131. [2]丁从明,吴羽佳,秦姝媛,梁甄桥.社会信任与公共政策的实施效率——基于农村居民新农保参与的微观证据[J].中国农村经济,2019(05):109-123. [3]胡新艳,陈小知,米运生.农地整合确权政策对农业规模经营发展的影响评估——来自准自然实验的证据[J].中国农村经济,2018(12):83-102. [4]周振,张琛,彭超,孔祥智.农业机械化与农民收入:来自农机具购置补贴政策的证据[J].中国农村经济,2016(02):68-82. 国际贸易问题 [1]曾守桢,余官胜.行政审批简化与我国对外直接投资增长——基于核准权下放试点的准自然实验实证研究[J].国际贸易问题,2020(04):19-34. [2]刘冲,张辉,吴群锋.进口竞争与企业产品专业化——基于中国多产品企业的研究[J].国际贸易问题,2020(03):22-39. [3]高翔,袁凯华.清洁生产环境规制与企业出口技术复杂度——微观证据与影响机制[J].国际贸易问题,2020(02):93-109. [4]吴嵩博,崔凡.融资约束与中国企业出口市场偏好——基于开发区准自然实验的实证分析[J].国际贸易问题,2020(02):157-174. [5]杨珍增,杨宏.美国“301调查”征税清单调整的政治经济学分析[J].国际贸易问题,2020(01):82-93. [6]张彩云.科技标准型环境规制与企业出口动态——基于清洁生产标准的一次自然实验[J].国际贸易问题,2019(12):32-45. [7]王毅,黄先海,余骁.环境规制是否降低了中国企业出口国内附加值率[J].国际贸易问题,2019(10):117-131. [8]兰健,张洪胜.集群商业信用与出口产品质量——来自中国企业层面的证据[J].国际贸易问题,2019(09):12-25. [9]黄先海,王煌,陈航宇.人口集聚如何影响出口企业加成率:理论机制与经验证据[J].国际贸易问题,2019(07):1-18. [10]张鹏杨,李众宜,毛海涛.产业政策如何影响企业出口二元边际[J].国际贸易问题,2019(07):47-62. [11]孙林,胡玲菲,方巧云.中国*贸易区战略提升中国进口食品质量了吗——基于双重差分模型[J].国际贸易问题,2019(05):54-68. [12]胡浩然.产业政策如何影响出口企业绩效——基于出口加工区企业样本的准自然实验[J].国际贸易问题,2018(12):27-38. [13]章韬,戚人杰.集聚-出口双促进政策的溢出效应——来自出口加工区的微观企业证据[J].国际贸易问题,2017(03):26-38. [14]彭冬冬,杜运苏.中间品贸易*化、融资约束与贸易方式转型[J].国际贸易问题,2016(12):52-63. [15]杜艳,周茂,李雨浓.贸易*化能否提高中国制造业企业资源再配置效率——基于中国加入WTO的倍差法分析[J].国际贸易问题,2016(09):38-49. [16]项后军,何康.自贸区的影响与资本流动——以上海为例的自然实验研究[J].国际贸易问题,2016(08):3-15. [17]刘啟仁,黄建忠.贸易*化、企业动态与行业生产率变化——基于我国加入WTO的自然实验[J].国际贸易问题,2016(01):27-37. [18]申萌,曾燕萍,曲如晓.环境规制与企业出口:来自千家企业节能行动的微观证据[J].国际贸易问题,2015(08):43-50. 南开管理评论 [1]田利辉,王可第.腐败惩治的正外部性和企业创新行为[J].南开管理评论,2020,23(02):121-131+154. [2]胡宁,王雪方,孙莲珂,靳庆鲁.房产限购政策有助于实体企业“脱虚返实”吗——基于双重差分研究设计[J].南开管理评论,2019,22(04):20-31. [3]马惠娴,佟爱琴.卖空机制对高管薪酬契约的治理效应——来自融资融券制度的准自然实验[J].南开管理评论,2019,22(02):61-74. [4]何威风,陈莉萍,刘巍.业绩考核制度会影响企业盈余管理行为吗[J].南开管理评论,2019,22(01):17-30. [5]田轩,孟清扬.股权激励计划能促进企业创新吗[J].南开管理评论,2018,21(03):176-190. [6]陈怡欣,张俊瑞,汪方军.卖空机制对上市公司创新的影响研究——基于我国融资融券制度的自然实验[J].南开管理评论,2018,21(02):62-74. [7]黄俊,黄超,位豪强,王敏.卖空机制提高了分析师盈余预测质量吗——基于融资融券制度的经验证据[J].南开管理评论,2018,21(02):135-148. [8]孙光国,孙瑞琦.控股股东委派执行董事能否提升公司治理水平[J].南开管理评论,2018,21(01):88-98+108. [9]沈洪涛,周艳坤.环境执法监督与企业环境绩效:来自环保约谈的准自然实验证据[J].南开管理评论,2017,20(06):73-82. [10]李茫茫,黎文靖.审计具有保险功能吗——基于*官员变更的自然实验[J].南开管理评论,2017,20(04):93-104. [11]陈运森,郑登津.董事网络关系、信息桥与投资趋同[J].南开管理评论,2017,20(03):159-171. [12]贾凡胜,吴昱,廉柯赟.股利税差别化、现金分红与代理问题——基于财税[2012]85号文件的研究[J].南开管理评论,2016,19(01):142-154. [13]徐莉萍,辛宇.媒体治理与中小投资者保护[J].南开管理评论,2011,14(06):36-47+94. 管理科学学报 [1]李沁洋,许年行.资本市场对外开放与股价崩盘风险——来自沪港通的证据[J].管理科学学报,2019,22(08):108-126. [2]张岩,吴芳,吴晓晖.IPO募资双重管制与资源配置——基于自然实验的经验证据[J].管理科学学报,2018,21(11):76-91. [3]刘志红,王艺明.“省直管县”改革能否提升县级财力水平?[J].管理科学学报,2018,21(10):1-13. [4]陈胜蓝,卢锐.卖空压力与控股股东私利侵占——来自卖空管制放松的准自然实验证据[J].管理科学学报,2018,21(04):67-85. [5]金宇超,靳庆鲁,严青蕾.合谋与胁迫:作为经济主体的媒体行为——基于新闻敲诈曝光的事件研究[J].管理科学学报,2018,21(03):1-22. [6]才静涵,夏乐.卖空制度、流动性与信息不对称问题研究——香港市场的个案[J].管理科学学报,2011,14(02):71-85. [7]王志强,吴世农.我国股票市场透明度变革效应研究[J].管理科学学报,2008,11(05):110-119. 社会学研究 [1]哈巍,赵颖.教学相“涨”:高校学生成绩和评教分数双重膨胀研究[J].社会学研究,2019,34(01):84-105+243-244. [2]程诚.同伴社会资本与学业成就——基于随机分配自然实验的案例分析[J].社会学研究,2017,32(06):141-164+245. 中国的准自然实验真多!
-
红梦电视系统闪烁包
-
万里红范红光:开发操作系统不能简单替代开源红梦的必要性
-
平衡二叉树、红黑树、B 树、B+ 树 - 前言
-
开放omeny 红梦笔记
-
红梦发展在行动:[故障日志小工具]
-
红梦 NEXT 发展实践:[视频文件裁剪
-
运行红梦操作系统系列小云演绎(六):分布式软总线发现+COAP全流程