text: #include <arch/interrupt.h>
  #include <arch/page.h>
  #include <arch/cpu.h>
  #include <arch/task.h>
  #include <arch/phymem.h>
  #include <xbook/task.h>
  #include <string.h>
  #include <string.h>
  #include <assert.h>
  #include <xbook/debug.h>
  #include <xbook/schedule.h>
  #include <xbook/spinlock.h>
  #include <xbook/mutexlock.h>
  #include <xbook/semaphore.h>
  #include <xbook/synclock.h>
  #include <xbook/fifobuf.h>
  #include <xbook/fifoio.h>
  #include <xbook/rwlock.h>
  #include <xbook/vmm.h>
  #include <xbook/mutexqueue.h>
  #include <xbook/process.h>
  #include <xbook/exception.h>
  #include <xbook/safety.h>
  #include <xbook/kernel.h>
  #include <xbook/fd.h>
  #include <math.h>
  #include <errno.h>
  
  static pid_t task_next_pid;
  LIST_HEAD(task_global_list);
  /* task init done flags, for early interrupt. */
  volatile int task_init_done = 0;
  
  pid_t task_take_pid()
  {
      return task_next_pid++;
  }
  
  void task_rollback_pid()
  {
      --task_next_pid;
  }
  
  void task_init(task_t *task, char *name, uint8_t prio_level)
  {
      memset(task, 0, sizeof(task_t));
      strcpy(task->name, name);
      task->state = TASK_READY;
      spinlock_init(&task->lock);
      task->static_priority = sched_calc_base_priority(prio_level);
      task->priority = task->static_priority;
      //task->timeslice = TASK_TIMESLICE_BASE + (task->priority / 10);
      task->timeslice = TASK_TIMESLICE_BASE + 1;
      task->ticks = task->timeslice;
      task->elapsed_ticks = 0;
      task->syscall_ticks = task->syscall_ticks_delta = 0;
      task->vmm = NULL;
      task->pid = task_take_pid();
      task->tgid = task->pid; /* 默认都是主线程，需要的时候修改 */
      task->pgid = -1;
      task->parent_pid = -1;
      task->exit_status = 0;
      // set kernel stack as the top of task mem struct
      task->kstack = (unsigned char *)(((unsigned long )task) + TASK_KERN_STACK_SIZE);
      task->flags = 0;
      fpu_init(&task->fpu, 0);
      timer_init(&task->sleep_timer, 0, NULL, NULL);
      alarm_init(&task->alarm);
      exception_manager_init(&task->exception_manager);
      task->errcode = 0;
      task->pthread = NULL;
      task->fileman = NULL;
      task->exit_hook = NULL;
      task->exit_hook_arg = NULL;
      task->port_comm = NULL;
      task->stack_magic = TASK_STACK_MAGIC;
  }
  
  void task_free(task_t *task)
  {
      list_del(&task->global_list);
      mem_free(task);
  }
  
  void task_add_to_global_list(task_t *task)
  {
      assert(!list_find(&task->global_list, &task_global_list));
      list_add_tail(&task->global_list, &task_global_list);
  }
  
  void task_set_timeslice(task_t *task, uint32_t timeslice)
  {
      if (task) {
          if (timeslice < TASK_TIMESLICE_MIN)
              timeslice = TASK_TIMESLICE_MIN;
          if (timeslice > TASK_TIMESLICE_MAX)
              timeslice = TASK_TIMESLICE_MAX;
          spin_lock(&task->lock);
          task->timeslice = timeslice;
          spin_unlock(&task->lock);
          
      }
  }
  
  task_t *task_find_by_pid(pid_t pid)
  {
      task_t *task;
      unsigned long flags;
      interrupt_save_and_disable(flags);
      list_for_each_owner(task, &task_global_list, global_list) {
          if (task->pid == pid) {
              interrupt_restore_state(flags);
              return task;
          }
      }
      interrupt_restore_state(flags);
      return NULL;
  }
  
  int task_is_child(pid_t pid, pid_t child_pid)
  {
      task_t *child = task_find_by_pid(child_pid);
      if (!child)
          return 0;
      return (child->parent_pid == pid);
  }
  
  /**
   * task_create - 启动一个内核线程
   * @name: 线程的名字
   * @prio_level: 线程优先级
   * @func: 线程入口
   * @arg: 线程参数
   * 
   * @return: 成功返回任务的指针，失败返回NULL
   */
  task_t *task_create(char *name, uint8_t prio_level, task_func_t *func, void *arg)
  {
      task_t *task = (task_t *) mem_alloc(TASK_KERN_STACK_SIZE);
      if (!task)
          return NULL;
      task_init(task, name, prio_level);
      task->flags |= THREAD_FLAG_KERNEL;
      if (fs_fd_init(task) < 0) {
          mem_free(task);
          return NULL;
      }
      task_stack_build(task, func, arg);
      unsigned long flags;
      interrupt_save_and_disable(flags);
      task_add_to_global_list(task);
      sched_unit_t *su = sched_get_cur_unit();
      sched_queue_add_tail(su, task);
      interrupt_restore_state(flags);
      return task;
  }
  
  void task_exit(int status)
  {
      unsigned long flags;
      interrupt_save_and_disable(flags);
      task_t *cur = task_current;
      if (cur->pid == USER_INIT_PROC_ID) {
          dbgprint("init proc can't exit!\n");
          interrupt_restore_state(flags);
          return;
      }
      cur->exit_status = status;
      task_do_cancel(cur);
      task_exit_hook(cur);
      cur->parent_pid = USER_INIT_PROC_ID;
      task_t *parent = task_find_by_pid(cur->parent_pid); 
      if (parent) {
          if (parent->state == TASK_WAITING) {
              interrupt_restore_state(flags);
              task_unblock(parent);
              task_block(TASK_HANGING);
          } else {
              interrupt_restore_state(flags);
              task_block(TASK_ZOMBIE);
          }
      } else {
          interrupt_restore_state(flags);
          task_block(TASK_ZOMBIE); 
      }
  }
  
  void task_activate_when_sched(task_t *task)
  {
      assert(task != NULL);
      spin_lock(&task->lock);
      task->state = TASK_RUNNING;
      spin_unlock(&task->lock);
      vmm_active(task->vmm);
  }
  
  void task_block(task_state_t state)
  {
      unsigned long flags;
      interrupt_save_and_disable(flags);
      assert((state == TASK_BLOCKED) || 
              (state == TASK_WAITING) || 
              (state == TASK_STOPPED) ||
              (state == TASK_HANGING) ||
              (state == TASK_ZOMBIE));
      task_t *current = task_current;
      current->state = state;    
      schedule();
      interrupt_restore_state(flags);
  }
  
  void task_unblock(task_t *task)
  {
      unsigned long flags;
      interrupt_save_and_disable(flags);
      if (!((task->state == TASK_BLOCKED) || 
          (task->state == TASK_WAITING) ||
          (task->state == TASK_STOPPED))) {
          panic("task_unblock: task name=%s pid=%d state=%d\n", task->name, task->pid, task->state);
      }
      if (task->state != TASK_READY) {
          sched_unit_t *su = sched_get_cur_unit();
          assert(!sched_queue_has_task(su, task));
          if (sched_queue_has_task(su, task)) {
              panic("task_unblock: task has already in ready list!\n");
          }
          task->state = TASK_READY;
          task->priority = sched_calc_new_priority(task, 1);
          sched_queue_add_head(su, task);
      }
      interrupt_restore_state(flags);
  }
  
  void task_yield()
  {
      unsigned long flags;
      interrupt_save_and_disable(flags);
      task_current->state = TASK_READY;
      schedule();
      interrupt_restore_state(flags);
  }
  
  int task_count_children(task_t *parent)
  {
      int children = 0;
      task_t *child;
      list_for_each_owner (child, &task_global_list, global_list) {
          if (child->parent_pid == parent->pid && TASK_IS_SINGAL_THREAD(child)) {
              children++;
          }
      }
      return children;
  }
  
  int task_do_cancel(task_t *task)
  {
      timer_cancel(&task->sleep_timer);
      return 0;
  }
  
  /**
   * 内核主线程就是从boot到现在的执行流。到最后会演变成idle
   * 在这里，我们需要给与它一个身份，他才可以参与多线程调度
   */
  static void task_init_boot_idle(sched_unit_t *su)
  {
      su->idle = (task_t *) KERNEL_STATCK_BOTTOM;
      task_init(su->idle, "idle0", TASK_PRIO_LEVEL_REALTIME);
      /* 需要在后面操作文件，因此需要初始化文件描述符表 */
      if (fs_fd_init(su->idle) < 0) { 
          panic("init kmain fs fd failed!\n");
      }
      su->idle->state = TASK_RUNNING;
      task_add_to_global_list(su->idle);
      
      su->cur = su->idle;
  }
  
  pid_t task_get_pid(task_t *task)
  {
      return task->tgid;
  }
  
  /* 
  当调用者为进程时，tgid=pid
  当调用者为线程时，tgid=master process pid
  也就是说，线程返回的是主线程（进程）的pid
  */
  pid_t sys_get_pid()
  {
      return task_get_pid(task_current);
  }
  
  pid_t sys_get_ppid()
  {
      return task_current->parent_pid;
  }
  
  /* 由于最小粒度是线程，所以，线程id=pid。 */
  pid_t sys_get_tid()
  {
      return task_current->pid;
  }
  
  /**
   * 设置pgid时，进程只能为自己和子进程设置pgid
   */
  int sys_set_pgid(pid_t pid, pid_t pgid)
  {
      if (pid < 0 || pgid < -1)
          return -EINVAL;
      task_t *task = NULL;
      task_t *cur = task_current;
      
      if (!pid) { /* pid=0：get current task pgid */
          task = cur;
      } else {
          task = task_find_by_pid(pid);
          if (!task)
              return -ESRCH;
      }
      if (!pgid) {    /* 使用pid对应进程的pid */
          pgid = task->pid;
      }
      /* pid不是自己的子进程或者是自己就退出 */
      if (task->pid != cur->pid && !task_is_child(cur->pid, task->pid))
          return -EPERM;
      task->pgid = pgid;
      return 0;
  }
  
  pid_t sys_get_pgid(pid_t pid)
  {
      if (pid < 0)
          return -EINVAL;
      task_t *task = NULL;
      if (!pid) { /* pid=0：get current task pgid */
          task = task_current;
      } else {
          task = task_find_by_pid(pid);
          if (!task)
              return -ESRCH;
      }
      return task->pgid;
  }
  
  void tasks_print()
  {
      keprint("\n----Task----\n");
      task_t *task;
      list_for_each_owner(task, &task_global_list, global_list) {
          keprint("name %s pid %d ppid %d state %d\n", 
              task->name, task->pid, task->parent_pid,  task->state);
      }
  }
  
  int sys_tstate(tstate_t *ts, unsigned int *idx)
  {
      if (!ts || !idx)
          return -EINVAL;
      unsigned int index;
      if (mem_copy_from_user(&index, idx, sizeof(unsigned int)) < 0)
          return -EINVAL;
      task_t *task;
      tstate_t tmp_ts;
      int n = 0;
      list_for_each_owner (task, &task_global_list, global_list) {
          if (n == index) {
              tmp_ts.ts_pid = task->pid;
              tmp_ts.ts_ppid = task->parent_pid;
              tmp_ts.ts_pgid = task->pgid;
              tmp_ts.ts_tgid = task->tgid;
              tmp_ts.ts_state = task->state;
              tmp_ts.ts_priority = task->priority;
              tmp_ts.ts_timeslice = task->timeslice;
              tmp_ts.ts_runticks = task->elapsed_ticks;
              memset(tmp_ts.ts_name, 0, PROC_NAME_LEN);
              strcpy(tmp_ts.ts_name, task->name);
              ++index;
              if (mem_copy_to_user(ts, &tmp_ts, sizeof(tstate_t)) < 0)
                  return -EINVAL;
              if (mem_copy_to_user(idx, &index, sizeof(unsigned int)) < 0)
                  return -EINVAL;
              return 0;
          }
          n++;
      }
      return -ESRCH;
  }
  
  int task_set_cwd(task_t *task, const char *path)
  {
      if (!task || !path)
          return -EINVAL;
      int len = strlen(path);
      memset(task->fileman->cwd, 0, MAX_PATH);
      memcpy(task->fileman->cwd, path, min(len, MAX_PATH));
      return 0;
  }
  
  int sys_getver(char *buf, int len)
  {
      if (!buf || !len)
          return -EINVAL;
      char tbuf[32] = {0};
      strcpy(tbuf, KERNEL_NAME);
      strcat(tbuf, "-");
      strcat(tbuf, KERNEL_VERSION);
      if (mem_copy_to_user(buf, tbuf, min(len, strlen(tbuf))) < 0)
          return -EFAULT;
      return 0;
  }
  
  unsigned long sys_unid(int id)
  {
      unsigned long _id;
      /* id(0-7) pid(8-15) systicks(16-31) */
      _id = (id & 0xff) + ((task_current->pid & 0xff) << 8) + ((systicks & 0xffff) << 16);
      return _id;
  }
  
  void task_dump(task_t *task)
  {
      keprint("----Task----\n");
      keprint("name:%s pid:%d parent pid:%d state:%d\n", task->name, task->pid, task->parent_pid, task->state);
      keprint("exit code:%d stack magic:%d\n", task->exit_status, task->stack_magic);
  }
  
  void kern_do_idle(void *arg)
  {
      while (1) {
          cpu_idle();
          schedule();
      }
  }
  
  #define INIT_SBIN_PATH  "/sbin/init"
  
  static char *init_argv[2] = {INIT_SBIN_PATH, 0};
  
  /**
   * 在初始化的最后调用，当前任务演变成"idle"任务，等待随时调动
   */
  void task_start_user()
  {
      keprint(PRINT_DEBUG "[task]: start user process.\n");
      task_t *proc = process_create(init_argv, NULL, PROC_CREATE_INIT);
      if (proc == NULL)
          panic("kernel start process failed! please check initsrv!\n");
      
      sched_unit_t *su = sched_get_cur_unit();
  	unsigned long flags;
      interrupt_save_and_disable(flags);
      su->idle->static_priority = su->idle->priority = TASK_PRIORITY_LOW;
      interrupt_restore_state(flags);
      schedule();
      interrupt_enable();
      kern_do_idle(NULL);
  }
  
  void tasks_init()
  {
      task_next_pid = 0;
      sched_unit_t *su = sched_get_cur_unit();
      task_init_boot_idle(su);
      task_take_pid(); /* 跳过pid1，预留给INIT进程 */
      task_init_done = 1;
      keprint(PRINT_INFO "[ok] tasks init.");
  }
  