/* * The slave flusher thread pulls work off the master flush list until no * work is left. */ static void hammer_flusher_slave_thread(void *arg) { hammer_flush_group_t flg; hammer_flusher_info_t info; hammer_mount_t hmp; info = arg; hmp = info->hmp; lwkt_gettoken(&hmp->fs_token); for (;;) { while (info->runstate == 0) tsleep(&info->runstate, 0, "hmrssw", 0); if (info->runstate < 0) break; flg = info->flg; RB_SCAN(hammer_fls_rb_tree, &flg->flush_tree, NULL, hammer_flusher_flush_inode, info); info->runstate = 0; info->flg = NULL; TAILQ_REMOVE(&hmp->flusher.run_list, info, entry); TAILQ_INSERT_TAIL(&hmp->flusher.ready_list, info, entry); wakeup(&hmp->flusher.ready_list); } info->td = NULL; wakeup(&info->td); lwkt_reltoken(&hmp->fs_token); lwkt_exit(); }
/* * The master flusher thread manages the flusher sequence id and * synchronization with the slave work threads. */ static void hammer_flusher_master_thread(void *arg) { hammer_mount_t hmp; int seq; int nomore; hmp = arg; lwkt_gettoken(&hmp->fs_token); for (;;) { /* * Flush all sequence numbers up to but not including .next, * or until an open flush group is encountered. */ for (;;) { while (hmp->flusher.group_lock) tsleep(&hmp->flusher.group_lock, 0, "hmrhld",0); hammer_flusher_clean_loose_ios(hmp); seq = hammer_flusher_flush(hmp, &nomore); hmp->flusher.done = seq; wakeup(&hmp->flusher.done); if (hmp->flags & HAMMER_MOUNT_CRITICAL_ERROR) break; if (nomore) break; } /* * Wait for activity. */ if (hmp->flusher.exiting && TAILQ_EMPTY(&hmp->flush_group_list)) break; while (hmp->flusher.signal == 0) tsleep(&hmp->flusher.signal, 0, "hmrwwa", 0); hmp->flusher.signal = 0; } /* * And we are done. */ hmp->flusher.td = NULL; wakeup(&hmp->flusher.exiting); lwkt_reltoken(&hmp->fs_token); lwkt_exit(); }
/* * Destroy an LWKT thread. Warning! This function is not called when * a process exits, cpu_proc_exit() directly calls cpu_thread_exit() and * uses a different reaping mechanism. * * XXX duplicates lwkt_exit() */ void kthread_exit(void) { lwkt_exit(); }