+ snprintf(name, size, "%s_%s.%s", logname, logtype, suf);
+}
+
+static int check_waitees(char *waitee)
+{
+ struct thread_data *td;
+ int i, ret = 0;
+
+ for_each_td(td, i) {
+ if (td->subjob_number)
+ continue;
+
+ ret += !strcmp(td->o.name, waitee);
+ }
+
+ return ret;
+}
+
+static bool wait_for_ok(const char *jobname, struct thread_options *o)
+{
+ int nw;
+
+ if (!o->wait_for)
+ return true;
+
+ if (!strcmp(jobname, o->wait_for)) {
+ log_err("%s: a job cannot wait for itself (wait_for=%s).\n",
+ jobname, o->wait_for);
+ return false;
+ }
+
+ if (!(nw = check_waitees(o->wait_for))) {
+ log_err("%s: waitee job %s unknown.\n", jobname, o->wait_for);
+ return false;
+ }
+
+ if (nw > 1) {
+ log_err("%s: multiple waitees %s found,\n"
+ "please avoid duplicates when using wait_for option.\n",
+ jobname, o->wait_for);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Adds a job to the list of things todo. Sanitizes the various options
+ * to make sure we don't have conflicts, and initializes various
+ * members of td.
+ */
+static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
+ int recursed, int client_type)
+{
+ unsigned int i;
+ char fname[PATH_MAX];
+ int numjobs, file_alloced;
+ struct thread_options *o = &td->o;
+ char logname[PATH_MAX + 32];
+
+ /*
+ * the def_thread is just for options, it's not a real job
+ */
+ if (td == &def_thread)
+ return 0;
+
+ init_flags(td);
+
+ /*
+ * if we are just dumping the output command line, don't add the job
+ */
+ if (parse_dryrun()) {
+ put_job(td);
+ return 0;
+ }
+
+ td->client_type = client_type;
+
+ if (profile_td_init(td))
+ goto err;
+
+ if (ioengine_load(td))
+ goto err;
+
+ file_alloced = 0;
+ if (!o->filename && !td->files_index && !o->read_iolog_file) {
+ file_alloced = 1;
+
+ if (o->nr_files == 1 && exists_and_not_regfile(jobname))
+ add_file(td, jobname, job_add_num, 0);
+ else {
+ for (i = 0; i < o->nr_files; i++)
+ add_file(td, make_filename(fname, sizeof(fname), o, jobname, job_add_num, i), job_add_num, 0);
+ }
+ }
+
+ if (fixup_options(td))
+ goto err;
+
+ /*
+ * Belongs to fixup_options, but o->name is not necessarily set as yet
+ */
+ if (!wait_for_ok(jobname, o))
+ goto err;
+
+ flow_init_job(td);
+
+ /*
+ * IO engines only need this for option callbacks, and the address may
+ * change in subprocesses.
+ */
+ if (td->eo)
+ *(struct thread_data **)td->eo = NULL;
+
+ if (td_ioengine_flagged(td, FIO_DISKLESSIO)) {
+ struct fio_file *f;
+
+ for_each_file(td, f, i)
+ f->real_file_size = -1ULL;
+ }
+
+ td->mutex = fio_mutex_init(FIO_MUTEX_LOCKED);
+
+ td->ts.clat_percentiles = o->clat_percentiles;
+ td->ts.percentile_precision = o->percentile_precision;
+ memcpy(td->ts.percentile_list, o->percentile_list, sizeof(o->percentile_list));