Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[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: 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 120 additions and 65 deletions.
71 changes: 46 additions & 25 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);
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;
}
else {
log_debug("SLEEP %ld milliseconds; from %s:%d: %s()",
ms, file, line, func);

if( tot_ms <= 0 ) {
res = WAIT_TIMEOUT;
goto EXIT;
}

do {
if( worker_bailing_out() ) {
log_warning("SLEEP %ld milliseconds - ignored; from %s:%d: %s()",
ms, file, line, func);
log_warning("wait canceled");
goto EXIT;
}

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
92 changes: 58 additions & 34 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;
}

for( int attempts = 3; ; ) {
if( (ack = !worker_is_mtpd_running()) ) {
log_debug("mtp daemon has stopped");
break;
goto FAILURE;
}

if( --attempts <= 0) {
if( common_wait(worker_mtp_stop_delay, worker_mtpd_stopped_p, 0) != WAIT_READY ) {
log_warning("failed to stop mtp daemon; giving up");
break;
goto FAILURE;
}

log_debug("waiting for mtp daemon to stop");
common_msleep(2000);
}
EXIT:
log_debug("mtp daemon has stopped");

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;
}

for( int attempts = 15; ; ) {
if( (ack = worker_is_mtpd_running()) ) {
log_debug("mtp daemon has started");
break;
goto FAILURE;
}

if( --attempts <= 0) {
if( common_wait(worker_mtp_start_delay, worker_mtpd_running_p, 0) != WAIT_READY ) {
log_warning("failed to start mtp daemon; giving up");
break;
goto FAILURE;
}

log_debug("waiting for mtp daemon to start");
common_msleep(2000);
}
EXIT:
log_debug("mtp daemon has started");

SUCCESS:
ack = true;

FAILURE:
return ack;
}

Expand Down

0 comments on commit 566b7a6

Please sign in to comment.