Move the statfvs() call in a separate thread

statvfs can block, so run it in a thread to not stall the E mainloop
This commit is contained in:
Davide Andreoli 2020-11-12 07:07:28 +01:00
parent b25c7c5529
commit b682a5f902
1 changed files with 111 additions and 25 deletions

View File

@ -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 *