Commit 566b7a6e authored by spiiroin's avatar spiiroin

[worker] Adjust mtp daemon start/stop timeouts

In devices that have lots of files (say tens of thousands), mtp daemon
might have trouble getting everything enumerated within 30 second timeout
allowed by usb-moded.

Use 2 minute timeout for starting, and 15 second timeout for stopping
mtp daemon.

Implement a generic wait for condition/timeout function that can also
be interrupted from main thread. Use the wait function for both regular
blocking sleeps and waiting for mtp daemon starting/stopping.
Signed-off-by: spiiroin's avatarSimo Piiroinen <simo.piiroinen@jollamobile.com>
parent 1d9e91e4
......@@ -52,7 +52,8 @@ void common_acquire_wakelock (const char *wakelock_name);
void common_release_wakelock (const char *wakelock_name);
int common_system_ (const char *file, int line, const char *func, const char *command);
FILE *common_popen_ (const char *file, int line, const char *func, const char *command, const char *type);
void common_usleep_ (const char *file, int line, const char *func, useconds_t usec);
waitres_t common_wait (unsigned tot_ms, bool (*ready_cb)(void *aptr), void *aptr);
bool common_msleep_ (const char *file, int line, const char *func, unsigned msec);
static bool common_mode_in_list (const char *mode, char *const *modes);
int common_valid_mode (const char *mode);
gchar *common_get_mode_list (mode_list_type_t type);
......@@ -338,40 +339,60 @@ common_popen_(const char *file, int line, const char *func,
return popen(command, type);
}
/** Wrapper to give visibility to blocking sleeps usb-moded is making
*/
void
common_usleep_(const char *file, int line, const char *func,
useconds_t usec)
waitres_t
common_wait(unsigned tot_ms, bool (*ready_cb)(void *aptr), void *aptr)
{
struct timespec ts = {
.tv_sec = (usec / 1000000),
.tv_nsec = (usec % 1000000) * 1000
};
struct timespec ts;
long ms = (ts.tv_nsec + 1000000 - 1) / 1000000;
waitres_t res = WAIT_FAILED;
if( !ms ) {
log_debug("SLEEP %ld seconds; from %s:%d: %s()",
(long)ts.tv_sec, file, line, func);
}
else if( ts.tv_sec ) {
log_debug("SLEEP %ld.%03ld seconds; from %s:%d: %s()",
(long)ts.tv_sec, ms, file, line, func);
}
else {
log_debug("SLEEP %ld milliseconds; from %s:%d: %s()",
ms, file, line, func);
}
for( ;; ) {
unsigned nap_ms = (tot_ms > 200) ? 200 : tot_ms;
ts.tv_sec = (nap_ms / 1000);
ts.tv_nsec = (nap_ms % 1000);
ts.tv_nsec *= 1000 * 1000;
for( ;; ) {
if( ready_cb && ready_cb(aptr) ) {
res = WAIT_READY;
goto EXIT;
}
if( tot_ms <= 0 ) {
res = WAIT_TIMEOUT;
goto EXIT;
}
if( worker_bailing_out() ) {
log_warning("wait canceled");
goto EXIT;
}
do {
if( worker_bailing_out() ) {
log_warning("SLEEP %ld milliseconds - ignored; from %s:%d: %s()",
ms, file, line, func);
break;
if( nanosleep(&ts, &ts) == 0 )
break;
if( errno != EINTR ) {
log_warning("wait failed: %m");
goto EXIT;
}
}
} while( nanosleep(&ts, &ts) == -1 && errno != EINTR );
tot_ms -= nap_ms;
}
EXIT:
return res;
}
/** Wrapper to give visibility to blocking sleeps usb-moded is making
*/
bool
common_msleep_(const char *file, int line, const char *func, unsigned msec)
{
log_debug("SLEEP %u.%03u seconds; from %s:%d: %s()",
msec / 1000u, msec % 1000u,file, line, func);
return common_wait(msec, 0, 0) == WAIT_TIMEOUT;
}
/* ------------------------------------------------------------------------- *
......
......@@ -2,6 +2,7 @@
# define USB_MODED_COMMON_H_
# include <stdio.h>
# include <stdbool.h>
# include <glib.h>
/* ========================================================================= *
......@@ -25,6 +26,13 @@ typedef enum {
CABLE_STATE_NUMOF
} cable_state_t;
typedef enum waitres_t
{
WAIT_FAILED,
WAIT_READY,
WAIT_TIMEOUT,
} waitres_t;
/* ========================================================================= *
* Functions
* ========================================================================= */
......@@ -45,7 +53,8 @@ void common_acquire_wakelock (const char *wakelock_name);
void common_release_wakelock (const char *wakelock_name);
int common_system_ (const char *file, int line, const char *func, const char *command);
FILE *common_popen_ (const char *file, int line, const char *func, const char *command, const char *type);
void common_usleep_ (const char *file, int line, const char *func, useconds_t usec);
waitres_t common_wait (unsigned tot_ms, bool (*ready_cb)(void *aptr), void *aptr);
bool common_msleep_ (const char *file, int line, const char *func, unsigned msec);
int common_valid_mode (const char *mode);
gchar *common_get_mode_list (mode_list_type_t type);
......@@ -55,8 +64,7 @@ gchar *common_get_mode_list (mode_list_type_t type);
# define common_system(command) common_system_(__FILE__,__LINE__,__FUNCTION__,(command))
# define common_popen(command, type) common_popen_(__FILE__,__LINE__,__FUNCTION__,(command),(type))
# define common_usleep(usec) common_usleep_(__FILE__,__LINE__,__FUNCTION__,(usec))
# define common_msleep(msec) common_usleep_(__FILE__,__LINE__,__FUNCTION__,(msec)*1000)
# define common_sleep(sec) common_usleep_(__FILE__,__LINE__,__FUNCTION__,(sec)*1000000)
# define common_msleep(msec) common_msleep_(__FILE__,__LINE__,__FUNCTION__,(msec))
# define common_sleep(sec) common_msleep_(__FILE__,__LINE__,__FUNCTION__,(sec)*1000)
#endif /* USB_MODED_COMMON_H_ */
......@@ -774,7 +774,8 @@ bool modesetting_enter_dynamic_mode(void)
/* In case of failure, retry upto 3 times */
for( int i = 0; error && i < 3; ++i ) {
log_warning("Retry setting up the network");
common_msleep(1000);
if( !common_msleep(1000) )
break;
if( !(error = network_up(data)) )
log_warning("Setting up the network succeeded");
}
......
......@@ -533,7 +533,8 @@ gboolean connman_set_tethering(const char *path, gboolean on)
{
if (i>0)
{
common_msleep(200);
if( !common_msleep(200) )
break;
}
if (connman_try_set_tethering(connection, path, on))
{
......
......@@ -115,7 +115,7 @@ worker_thread_p(void)
bool
worker_bailing_out(void)
{
// ref: see common_usleep_()
// ref: see common_msleep_()
return worker_thread_p() && worker_bailout > 0;
}
......@@ -123,6 +123,26 @@ worker_bailing_out(void)
* MTP_DAEMON
* ------------------------------------------------------------------------- */
/** Maximum time to wait for mtpd to start [ms]
*
* This needs to include time to start systemd unit
* plus however long it might take for mtpd to scan
* all files exposed over mtp. On a slow device with
* lots of files it can easily take over 30 seconds,
* especially during the 1st mtp connect after reboot.
*
* Use two minutes as some kind of worst case estimate.
*/
static unsigned worker_mtp_start_delay = 120 * 1000;
/** Maximum time to wait for mtpd to stop [ms]
*
* This is just regular service stop. Expected to
* take max couple of seconds, but use someting
* in the ballbark of systemd default i.e. 15 seconds
*/
static unsigned worker_mtp_stop_delay = 15 * 1000;
static bool worker_mode_is_mtp_mode(const char *mode)
{
return mode && !strcmp(mode, "mtp_mode");
......@@ -155,73 +175,77 @@ static bool worker_is_mtpd_running(void)
return ack;
}
static bool
worker_mtpd_running_p(void *aptr)
{
(void)aptr;
return worker_is_mtpd_running();
}
static bool
worker_mtpd_stopped_p(void *aptr)
{
(void)aptr;
return !worker_is_mtpd_running();
}
static bool
worker_stop_mtpd(void)
{
bool ack = !worker_is_mtpd_running();
bool ack = false;
if( ack ) {
if( worker_mtpd_stopped_p(0) ) {
log_debug("mtp daemon is not running");
goto EXIT;
goto SUCCESS;
}
int rc = common_system("systemctl-user stop buteo-mtp.service");
if( rc != 0 ) {
log_warning("failed to stop mtp daemon; exit code = %d", rc);
goto EXIT;
goto FAILURE;
}
for( int attempts = 3; ; ) {
if( (ack = !worker_is_mtpd_running()) ) {
log_debug("mtp daemon has stopped");
break;
}
if( common_wait(worker_mtp_stop_delay, worker_mtpd_stopped_p, 0) != WAIT_READY ) {
log_warning("failed to stop mtp daemon; giving up");
goto FAILURE;
}
if( --attempts <= 0) {
log_warning("failed to stop mtp daemon; giving up");
break;
}
log_debug("mtp daemon has stopped");
log_debug("waiting for mtp daemon to stop");
common_msleep(2000);
}
EXIT:
SUCCESS:
ack = true;
FAILURE:
return ack;
}
static bool
worker_start_mtpd(void)
{
bool ack = worker_is_mtpd_running();
bool ack = false;
if( ack ) {
log_debug("mtp daemon is not running");
goto EXIT;
if( worker_mtpd_running_p(0) ) {
log_debug("mtp daemon is running");
goto SUCCESS;
}
int rc = common_system("systemctl-user start buteo-mtp.service");
if( rc != 0 ) {
log_warning("failed to start mtp daemon; exit code = %d", rc);
goto EXIT;
goto FAILURE;
}
for( int attempts = 15; ; ) {
if( (ack = worker_is_mtpd_running()) ) {
log_debug("mtp daemon has started");
break;
}
if( common_wait(worker_mtp_start_delay, worker_mtpd_running_p, 0) != WAIT_READY ) {
log_warning("failed to start mtp daemon; giving up");
goto FAILURE;
}
if( --attempts <= 0) {
log_warning("failed to start mtp daemon; giving up");
break;
}
log_debug("mtp daemon has started");
log_debug("waiting for mtp daemon to start");
common_msleep(2000);
}
EXIT:
SUCCESS:
ack = true;
FAILURE:
return ack;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment