+int jobs_invoke0(
+ int timeout,
+ void (*callback)(int signum))
+{
+ return jobs_invoke3(timeout, (void(*)(int,void*,void*,void*))callback, NULL, NULL, NULL);
+}
+
+int jobs_invoke(
+ int timeout,
+ void (*callback)(int, void*),
+ void *arg)
+{
+ return jobs_invoke3(timeout, (void(*)(int,void*,void*,void*))callback, arg, NULL, NULL);
+}
+
+int jobs_invoke2(
+ int timeout,
+ void (*callback)(int, void*, void*),
+ void *arg1,
+ void *arg2)
+{
+ return jobs_invoke3(timeout, (void(*)(int,void*,void*,void*))callback, arg1, arg2, NULL);
+}
+
+static void unlock_invoker(int signum, void *arg1, void *arg2, void *arg3)
+{
+ struct thread *t = arg1;
+ pthread_mutex_lock(&mutex);
+ t->stop = 1;
+ pthread_mutex_unlock(&mutex);
+}
+
+/* invoke the job to the 'callback' using a separate thread if available */
+int jobs_invoke3(
+ int timeout,
+ void (*callback)(int, void*, void *, void*),
+ void *arg1,
+ void *arg2,
+ void *arg3)
+{
+ const char *info;
+ struct job *job1, *job2;
+ int rc;
+ struct thread me;
+
+ pthread_mutex_lock(&mutex);
+
+ /* allocates the job */
+ job1 = job_create(&me, timeout, callback, arg1, arg2, arg3);
+ job2 = job_create(&me, 0, unlock_invoker, &me, NULL, NULL);
+ if (!job1 || !job2) {
+ errno = ENOMEM;
+ info = "out of memory";
+ goto error;
+ }
+
+ /* start a thread if needed */
+ rc = start_one_thread_if_needed();
+ if (rc < 0) {
+ /* failed to start threading */
+ info = "can't start first thread";
+ goto error;
+ }
+
+ /* queues the job */
+ job_add2(job1, job2);
+
+ /* run untill stopped */
+ thread_run(&me);
+ pthread_mutex_unlock(&mutex);
+ return 0;
+
+error:
+ if (job1) {
+ job1->next = free_jobs;
+ free_jobs = job1;
+ }
+ if (job2) {
+ job2->next = free_jobs;
+ free_jobs = job2;
+ }
+ ERROR("can't process job with threads: %s, %m", info);
+ pthread_mutex_unlock(&mutex);
+ return -1;
+}
+