From b682a5f9022614e935af8d3b6795cc01109f7eee Mon Sep 17 00:00:00 2001 From: Dave Andreoli Date: Thu, 12 Nov 2020 07:07:28 +0100 Subject: [PATCH] Move the statfvs() call in a separate thread statvfs can block, so run it in a thread to not stall the E mainloop --- src/e_mod_places.c | 136 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 111 insertions(+), 25 deletions(-) diff --git a/src/e_mod_places.c b/src/e_mod_places.c index 48c5b6c..75755da 100644 --- a/src/e_mod_places.c +++ b/src/e_mod_places.c @@ -17,8 +17,18 @@ #endif +/* Local Typedefs */ +typedef struct _FreespaceThreadData FreespaceThreadData; +struct _FreespaceThreadData +{ + const char *id; + const char *mount_point; + unsigned long long size; + unsigned long long free_space; +}; + /* Local Function Prototypes */ -static Eina_Bool _places_poller(void *data); +static Eina_Bool _places_freespace_timer_cb(void *data); static const char *_places_human_size_get(unsigned long long size); static void _places_volume_object_update(Volume *vol, Evas_Object *obj); static void _places_run_fm_external(const char *fm, const char *directory); @@ -30,9 +40,10 @@ void _places_eject_activated_cb(void *data, Evas_Object *o, const char *emission void _places_header_activated_cb(void *data, Evas_Object *o, const char *emission, const char *source); /* Local Variables */ -static Ecore_Timer *poller = NULL; static char theme_file[PATH_MAX]; -Eina_List *volumes = NULL; +static Eina_List *volumes = NULL; +static Ecore_Timer *freespace_timer = NULL; +static Ecore_Thread *freespace_thread = NULL; /* Implementation */ @@ -55,13 +66,22 @@ places_init(void) snprintf(theme_file, PATH_MAX, "%s/e-module-places.edj", places_conf->module->dir); - poller = ecore_timer_add(3.0, _places_poller, NULL); + freespace_timer = ecore_timer_add(3.0, _places_freespace_timer_cb, NULL); } void places_shutdown(void) { - if (poller) ecore_timer_del(poller); + if (freespace_timer) + { + ecore_timer_del(freespace_timer); + freespace_timer = NULL; + } + if (freespace_thread) + { + ecore_thread_cancel(freespace_thread); + freespace_thread = NULL; + } while (volumes) places_volume_del((Volume*)volumes->data); @@ -520,41 +540,107 @@ places_run_fm(const char *directory) /* Internals */ -static unsigned long long -_places_free_space_get(const char *mount, Volume *vol) +static void +_places_freespace_thread_run(void *data, Ecore_Thread *thread) { + /* statvfs can block, so we run it in a thread to not stall the E mainloop */ + Eina_List *l; + FreespaceThreadData *td = NULL; struct statvfs s; - if (!mount) return 0; - if (statvfs(mount, &s) != 0) - return 0; + // printf("PLACES: THIS RUN IN THREAD %p\n", thread); - if ((vol->size == 0) && (s.f_blocks)) - vol->size = (unsigned long long)s.f_blocks * (unsigned long long)s.f_frsize; + if (ecore_thread_check(thread) == EINA_TRUE) // thread cancelled + return; - return (unsigned long long)s.f_bavail * (unsigned long long)s.f_frsize; + EINA_LIST_FOREACH(data, l, td) + { + if (td->mount_point && (statvfs(td->mount_point, &s) == 0)) + { + td->size = (unsigned long long)s.f_blocks * (unsigned long long)s.f_frsize; + td->free_space = (unsigned long long)s.f_bavail * (unsigned long long)s.f_frsize; + } + if (ecore_thread_check(thread) == EINA_TRUE) + return; + } +} + +static void +_places_freespace_thread_done(void *data, Ecore_Thread *thread) +{ + FreespaceThreadData *td = NULL; + Volume *vol; + + EINA_LIST_FREE(data, td) + { + vol = places_volume_by_id_get(td->id); + if (vol) + { + // redraw only if size or free_space has changed more than 1Mb + if ((abs(td->free_space - vol->free_space) > 1024 * 1024) || + (abs(td->size - vol->size) > 1024 * 1024)) + { + vol->size = td->size; + vol->free_space = td->free_space; + places_volume_update(vol); + } + } + eina_stringshare_del(td->id); + eina_stringshare_del(td->mount_point); + E_FREE(td); + } + + // printf("PLACES: THREAD DONE %p\n", thread); + freespace_thread = NULL; +} + +static void +_places_freespace_thread_cancel(void *data, Ecore_Thread *thread) +{ + FreespaceThreadData *td = NULL; + + EINA_LIST_FREE(data, td) + { + eina_stringshare_del(td->id); + eina_stringshare_del(td->mount_point); + E_FREE(td); + } + freespace_thread = NULL; } static Eina_Bool -_places_poller(void *data) +_places_freespace_timer_cb(void *data EINA_UNUSED) { Volume *vol; - Eina_List *l; - long long new; + Eina_List *l, *tdl = NULL; + FreespaceThreadData *td = NULL; + + if (freespace_thread) + { + // printf("PLACES: *** SOMETHING WRONG *** thread:%p still running...\n", freespace_thread); + return ECORE_CALLBACK_RENEW; + } EINA_LIST_FOREACH(volumes, l, vol) - if (vol->valid && vol->mounted) { - new = _places_free_space_get(vol->mount_point, vol); - // redraw only if the size has changed more that 1Mb - if (abs(new - vol->free_space) > 1024 * 1024) + if (vol->valid && vol->mounted) { - vol->free_space = new; - places_volume_update(vol); + td = E_NEW(FreespaceThreadData, 1); + if (!td) return ECORE_CALLBACK_RENEW; + + td->id = eina_stringshare_add(vol->id); + td->mount_point = eina_stringshare_add(vol->mount_point); + tdl = eina_list_append(tdl, td); } - } - - return EINA_TRUE; + } + + if (tdl) + freespace_thread = ecore_thread_run(_places_freespace_thread_run, + _places_freespace_thread_done, + _places_freespace_thread_cancel, + tdl); + + return ECORE_CALLBACK_RENEW; } static const char *