File ChangeLog.LuaAPI changed (mode: 100644) (index 98e2c0eaf..80eb2fd87) |
... |
... |
documented in the regular ChangeLog. |
32 |
32 |
redirected (if it was redirected, i.e. original output wasn't connected to |
redirected (if it was redirected, i.e. original output wasn't connected to |
33 |
33 |
a TTY or character device on Windows). Thanks to gruvw. |
a TTY or character device on Windows). Thanks to gruvw. |
34 |
34 |
|
|
|
35 |
|
Made VifmJob:errors() wait for receiving errors if the job has finished. |
|
36 |
|
|
35 |
37 |
Fixed jobs created via vifm.startjob() being displayed with "UNKNOWN" for |
Fixed jobs created via vifm.startjob() being displayed with "UNKNOWN" for |
36 |
38 |
description on the job bar. |
description on the job bar. |
37 |
39 |
|
|
File data/vim/doc/app/vifm-lua.txt changed (mode: 100644) (index 0cdcf9b67..37c744484) |
1 |
|
*vifm-lua.txt* For Vifm version 1.0 Last change: 2024 Mar 2 |
|
|
1 |
|
*vifm-lua.txt* For Vifm version 1.0 Last change: 2024 Mar 11 |
2 |
2 |
|
|
3 |
3 |
Email for bugs and suggestions: <xaizek@posteo.net> |
Email for bugs and suggestions: <xaizek@posteo.net> |
4 |
4 |
|
|
|
... |
... |
doesn't wait for arrival of data. Empty if `mergestreams` was set to `true`. |
1259 |
1259 |
Return:~ |
Return:~ |
1260 |
1260 |
Returns a string. |
Returns a string. |
1261 |
1261 |
|
|
|
1262 |
|
Raises an error:~ |
|
1263 |
|
On failing to wait for errors of a finished job (timeout). |
|
1264 |
|
|
1262 |
1265 |
-------------------------------------------------------------------------------- |
-------------------------------------------------------------------------------- |
1263 |
1266 |
*vifm-l_VifmTab* |
*vifm-l_VifmTab* |
1264 |
1267 |
|
|
File src/background.c changed (mode: 100644) (index 523dbfc67..6aa8bd66a) |
30 |
30 |
#include <sys/wait.h> /* waitpid() */ |
#include <sys/wait.h> /* waitpid() */ |
31 |
31 |
#endif |
#endif |
32 |
32 |
#include <signal.h> /* SIG* kill() */ |
#include <signal.h> /* SIG* kill() */ |
33 |
|
#include <unistd.h> /* execve() fork() setsid() */ |
|
|
33 |
|
#include <unistd.h> /* execve() fork() setsid() usleep() */ |
34 |
34 |
|
|
35 |
35 |
#include <assert.h> /* assert() */ |
#include <assert.h> /* assert() */ |
36 |
36 |
#include <errno.h> /* errno */ |
#include <errno.h> /* errno */ |
|
... |
... |
free_drained_jobs(bg_job_t **jobs) |
546 |
546 |
if(!j->running) |
if(!j->running) |
547 |
547 |
{ |
{ |
548 |
548 |
--j->use_count; |
--j->use_count; |
|
549 |
|
j->erroring = 0; |
549 |
550 |
*job = j->err_next; |
*job = j->err_next; |
550 |
551 |
(void)pthread_spin_unlock(&j->status_lock); |
(void)pthread_spin_unlock(&j->status_lock); |
551 |
552 |
continue; |
continue; |
|
... |
... |
add_background_job(pid_t pid, const char cmd[], uintptr_t err, uintptr_t data, |
1407 |
1408 |
} |
} |
1408 |
1409 |
|
|
1409 |
1410 |
new->running = 1; |
new->running = 1; |
|
1411 |
|
new->erroring = 0; |
1410 |
1412 |
new->use_count = 0; |
new->use_count = 0; |
1411 |
1413 |
new->exit_code = -1; |
new->exit_code = -1; |
1412 |
1414 |
|
|
|
... |
... |
add_background_job(pid_t pid, const char cmd[], uintptr_t err, uintptr_t data, |
1426 |
1428 |
|
|
1427 |
1429 |
if(new->err_stream != NO_JOB_ID) |
if(new->err_stream != NO_JOB_ID) |
1428 |
1430 |
{ |
{ |
|
1431 |
|
new->erroring = 1; |
1429 |
1432 |
++new->use_count; |
++new->use_count; |
1430 |
1433 |
|
|
1431 |
1434 |
if(pthread_mutex_lock(&new_err_jobs_lock) != 0) |
if(pthread_mutex_lock(&new_err_jobs_lock) != 0) |
|
... |
... |
mark_job_finished(bg_job_t *job, int exit_code) |
1692 |
1695 |
} |
} |
1693 |
1696 |
} |
} |
1694 |
1697 |
|
|
|
1698 |
|
int |
|
1699 |
|
bg_job_wait_errors(bg_job_t *job) |
|
1700 |
|
{ |
|
1701 |
|
enum |
|
1702 |
|
{ |
|
1703 |
|
ERROR_SLEEP_US = 50, |
|
1704 |
|
ERROR_SLEEP_MAX_US = 50*1000, /* 50ms should be more than enough. */ |
|
1705 |
|
}; |
|
1706 |
|
|
|
1707 |
|
if(job->err_stream == NO_JOB_ID || bg_job_is_running(job)) |
|
1708 |
|
{ |
|
1709 |
|
return 0; |
|
1710 |
|
} |
|
1711 |
|
|
|
1712 |
|
/* Using active polling with a sleep to avoid adding a mutex and a conditional |
|
1713 |
|
* variable to every job with an error stream. The code below shouldn't run |
|
1714 |
|
* often. */ |
|
1715 |
|
|
|
1716 |
|
int i; |
|
1717 |
|
int erroring = 1; |
|
1718 |
|
for(i = 0; i < ERROR_SLEEP_MAX_US/ERROR_SLEEP_US && erroring; ++i) |
|
1719 |
|
{ |
|
1720 |
|
if(pthread_spin_lock(&job->status_lock) == 0) |
|
1721 |
|
{ |
|
1722 |
|
erroring = job->erroring; |
|
1723 |
|
(void)pthread_spin_unlock(&job->status_lock); |
|
1724 |
|
} |
|
1725 |
|
|
|
1726 |
|
if(erroring) |
|
1727 |
|
{ |
|
1728 |
|
poke_error_thread(); |
|
1729 |
|
usleep(ERROR_SLEEP_US); |
|
1730 |
|
} |
|
1731 |
|
} |
|
1732 |
|
|
|
1733 |
|
/* In case we've reached here and `erroring` is still non-zero, this could be |
|
1734 |
|
* a bug in handling jobs or the system is under heavy load. Either way, we |
|
1735 |
|
* probably shouldn't wait here forever, so return an error. */ |
|
1736 |
|
return erroring; |
|
1737 |
|
} |
|
1738 |
|
|
1695 |
1739 |
/* Wakes up error thread to process any changes to the jobs. */ |
/* Wakes up error thread to process any changes to the jobs. */ |
1696 |
1740 |
static void |
static void |
1697 |
1741 |
poke_error_thread(void) |
poke_error_thread(void) |
File src/background.h changed (mode: 100644) (index 470e2190d..e74972260) |
... |
... |
typedef struct bg_job_t |
97 |
97 |
/* The lock is meant to guard state-related fields. */ |
/* The lock is meant to guard state-related fields. */ |
98 |
98 |
pthread_spinlock_t status_lock; |
pthread_spinlock_t status_lock; |
99 |
99 |
int running; /* Whether this job is still running. */ |
int running; /* Whether this job is still running. */ |
|
100 |
|
int erroring; /* Whether error thread still handles this job. */ |
100 |
101 |
int use_count; /* Count of uses of this job entry. */ |
int use_count; /* Count of uses of this job entry. */ |
101 |
102 |
int exit_code; /* Exit code of external command. */ |
int exit_code; /* Exit code of external command. */ |
102 |
103 |
|
|
|
... |
... |
int bg_job_was_killed(bg_job_t *job); |
209 |
210 |
* Returns zero on success, otherwise non-zero is returned. */ |
* Returns zero on success, otherwise non-zero is returned. */ |
210 |
211 |
int bg_job_wait(bg_job_t *job); |
int bg_job_wait(bg_job_t *job); |
211 |
212 |
|
|
|
213 |
|
/* Waits until error thread is done with this job. The job might have nothing |
|
214 |
|
* to do with the error thread and might actually be running with errors still |
|
215 |
|
* comming, but it's possible that the job has exited and not all errors were |
|
216 |
|
* processed which is the interesting case. Returns zero on success or non-zero |
|
217 |
|
* on failure to wait for error thread to release the job (timeout). */ |
|
218 |
|
int bg_job_wait_errors(bg_job_t *job); |
|
219 |
|
|
212 |
220 |
/* Increases use counter of the job. Doing this prevents object deletion while |
/* Increases use counter of the job. Doing this prevents object deletion while |
213 |
221 |
* it's still in use. */ |
* it's still in use. */ |
214 |
222 |
void bg_job_incref(bg_job_t *job); |
void bg_job_incref(bg_job_t *job); |
File src/lua/vifmjob.c changed (mode: 100644) (index 5d4be919e..aa3b7dedf) |
... |
... |
VLUA_API(vifmjob_errors)(lua_State *lua) |
387 |
387 |
{ |
{ |
388 |
388 |
vifm_job_t *vifm_job = luaL_checkudata(lua, 1, "VifmJob"); |
vifm_job_t *vifm_job = luaL_checkudata(lua, 1, "VifmJob"); |
389 |
389 |
|
|
|
390 |
|
if(bg_job_wait_errors(vifm_job->job) != 0) |
|
391 |
|
{ |
|
392 |
|
return luaL_error(lua, "%s", "Failed to wait for errors of an exited job"); |
|
393 |
|
} |
|
394 |
|
|
390 |
395 |
char *errors = NULL; |
char *errors = NULL; |
391 |
396 |
pthread_spin_lock(&vifm_job->job->errors_lock); |
pthread_spin_lock(&vifm_job->job->errors_lock); |
392 |
397 |
update_string(&errors, vifm_job->job->errors); |
update_string(&errors, vifm_job->job->errors); |