Skip to content

Commit

Permalink
[worker] Adjust mtp daemon start/stop timeouts
Browse files Browse the repository at this point in the history
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: Simo Piiroinen <simo.piiroinen@jollamobile.com>
  • Loading branch information
spiiroin committed Sep 5, 2018
1 parent 1d9e91e commit 566b7a6
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 71 deletions.
79 changes: 50 additions & 29 deletions src/usb_moded-common.c
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}

/* ------------------------------------------------------------------------- *
Expand Down
16 changes: 12 additions & 4 deletions src/usb_moded-common.h
Expand Up @@ -2,6 +2,7 @@
# define USB_MODED_COMMON_H_

# include <stdio.h>
# include <stdbool.h>
# include <glib.h>

/* ========================================================================= *
Expand All @@ -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
* ========================================================================= */
Expand All @@ -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);

Expand All @@ -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_ */
3 changes: 2 additions & 1 deletion src/usb_moded-modesetting.c
Expand Up @@ -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");
}
Expand Down
3 changes: 2 additions & 1 deletion src/usb_moded-network.c
Expand Up @@ -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))
{
Expand Down
96 changes: 60 additions & 36 deletions src/usb_moded-worker.c
Expand Up @@ -115,14 +115,34 @@ worker_thread_p(void)
bool
worker_bailing_out(void)
{
// ref: see common_usleep_()
// ref: see common_msleep_()
return worker_thread_p() && worker_bailout > 0;
}

/* ------------------------------------------------------------------------- *
* 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");
Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit 566b7a6

Please sign in to comment.