void task_exithook(FAR _TCB *tcb, int status) { /* Under certain conditions, task_exithook() can be called multiple times. * A bit in the TCB was set the first time this function was called. If * that bit is set, then just ext doing nothing more.. */ if ((tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0) { return; } /* If exit function(s) were registered, call them now before we do any un- * initialization. NOTE: In the case of task_delete(), the exit function * will *not* be called on the thread execution of the task being deleted! */ task_atexit(tcb); /* Call any registered on_exit function(s) */ task_onexit(tcb, status); /* Leave the task group */ task_leavegroup(tcb, status); /* Wakeup any tasks waiting for this task to exit */ task_exitwakeup(tcb, status); /* Flush all streams (File descriptors will be closed when * the TCB is deallocated). */ #if CONFIG_NFILE_STREAMS > 0 (void)lib_flushall(&tcb->group->tg_streamlist); #endif /* Leave the task group. Perhaps discarding any un-reaped child * status (no zombies here!) */ #ifdef HAVE_TASK_GROUP group_leave(tcb); #endif /* Deallocate anything left in the TCB's queues */ #ifndef CONFIG_DISABLE_SIGNALS sig_cleanup(tcb); /* Deallocate Signal lists */ #endif /* This function can be re-entered in certain cases. Set a flag * bit in the TCB to not that we have already completed this exit * processing. */ tcb->flags |= TCB_FLAG_EXIT_PROCESSING; }
static void purge_empty_groups(Tox *m) { uint32_t i; for (i = 0; i < Tox_Bot.chats_idx; ++i) { if (!Tox_Bot.g_chats[i].active) continue; int num_peers = tox_group_number_peers(m, Tox_Bot.g_chats[i].num); if (num_peers <= 1) { fprintf(stderr, "Deleting empty group %i\n", Tox_Bot.g_chats[i].num); tox_del_groupchat(m, i); group_leave(i); } } }
static void cmd_leave(Tox *m, uint32_t friendnum, int argc, char (*argv)[MAX_COMMAND_LENGTH]) { const char *outmsg = NULL; if (!friend_is_master(m, friendnum)) { authent_failed(m, friendnum); return; } if (argc < 1) { outmsg = "Error: Group number required"; tox_friend_send_message(m, friendnum, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) outmsg, strlen(outmsg), NULL); return; } int groupnum = atoi(argv[1]); if (groupnum == 0 && strcmp(argv[1], "0")) { outmsg = "Error: Invalid group number"; tox_friend_send_message(m, friendnum, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) outmsg, strlen(outmsg), NULL); return; } if (!tox_conference_delete(m, groupnum, NULL)) { outmsg = "Error: Invalid group number"; tox_friend_send_message(m, friendnum, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) outmsg, strlen(outmsg), NULL); return; } char msg[MAX_COMMAND_LENGTH]; char name[TOX_MAX_NAME_LENGTH]; tox_friend_get_name(m, friendnum, (uint8_t *) name, NULL); size_t len = tox_friend_get_name_size(m, friendnum, NULL); name[len] = '\0'; group_leave(groupnum); printf("Left group %d (%s)\n", groupnum, name); snprintf(msg, sizeof(msg), "Left group %d", groupnum); tox_friend_send_message(m, friendnum, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) msg, strlen(msg), NULL); }
int task_init(FAR struct tcb_s *tcb, const char *name, int priority, FAR uint32_t *stack, uint32_t stack_size, main_t entry, FAR char * const argv[]) { FAR struct task_tcb_s *ttcb = (FAR struct task_tcb_s *)tcb; int errcode; int ret; /* Only tasks and kernel threads can be initialized in this way */ #ifndef CONFIG_DISABLE_PTHREAD DEBUGASSERT(tcb && (tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD); #endif /* Create a new task group */ #ifdef HAVE_TASK_GROUP ret = group_allocate(ttcb, tcb->flags); if (ret < 0) { errcode = -ret; goto errout; } #endif /* Associate file descriptors with the new task */ #if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 ret = group_setuptaskfiles(ttcb); if (ret < 0) { errcode = -ret; goto errout_with_group; } #endif /* Configure the user provided stack region */ up_use_stack(tcb, stack, stack_size); /* Initialize the task control block */ ret = task_schedsetup(ttcb, priority, task_start, entry, TCB_FLAG_TTYPE_TASK); if (ret < OK) { errcode = -ret; goto errout_with_group; } /* Setup to pass parameters to the new task */ (void)task_argsetup(ttcb, name, argv); /* Now we have enough in place that we can join the group */ #ifdef HAVE_TASK_GROUP ret = group_initialize(ttcb); if (ret < 0) { errcode = -ret; goto errout_with_group; } #endif return OK; errout_with_group: #ifdef HAVE_TASK_GROUP group_leave(tcb); errout: #endif set_errno(errcode); return ERROR; }
void task_exithook(FAR struct tcb_s *tcb, int status, bool nonblocking) { /* Under certain conditions, task_exithook() can be called multiple times. * A bit in the TCB was set the first time this function was called. If * that bit is set, then just exit doing nothing more.. */ if ((tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0) { return; } #if defined(CONFIG_SCHED_ATEXIT) || defined(CONFIG_SCHED_ONEXIT) /* If exit function(s) were registered, call them now before we do any un- * initialization. * * NOTES: * * 1. In the case of task_delete(), the exit function will *not* be called * on the thread execution of the task being deleted! That is probably * a bug. * 2. We cannot call the exit functions if nonblocking is requested: These * functions might block. * 3. This function will only be called with with non-blocking == true * only when called through _exit(). _exit() behaviors requires that * the exit functions *not* be called. */ if (!nonblocking) { task_atexit(tcb); /* Call any registered on_exit function(s) */ task_onexit(tcb, status); } #endif /* If the task was terminated by another task, it may be in an unknown * state. Make some feeble effort to recover the state. */ task_recover(tcb); /* Send the SIGCHILD signal to the parent task group */ task_signalparent(tcb, status); /* Wakeup any tasks waiting for this task to exit */ task_exitwakeup(tcb, status); /* If this is the last thread in the group, then flush all streams (File * descriptors will be closed when the TCB is deallocated). * * NOTES: * 1. We cannot flush the buffered I/O if nonblocking is requested. * that might cause this logic to block. * 2. This function will only be called with with non-blocking == true * only when called through _exit(). _exit() behavior does not * require that the streams be flushed */ if (!nonblocking) { task_flushstreams(tcb); } #ifdef HAVE_TASK_GROUP /* Leave the task group. Perhaps discarding any un-reaped child * status (no zombies here!) */ group_leave(tcb); #endif #ifndef CONFIG_DISABLE_SIGNALS /* Deallocate anything left in the TCB's queues */ sig_cleanup(tcb); /* Deallocate Signal lists */ #endif /* This function can be re-entered in certain cases. Set a flag * bit in the TCB to not that we have already completed this exit * processing. */ tcb->flags |= TCB_FLAG_EXIT_PROCESSING; }