[vlc-commits] commit: Win32: fix thread variable leaks ( =?UTF-8?Q?R=C3=A9mi=20Denis=2DCourmont=20?=)
git at videolan.org
git at videolan.org
Tue Nov 23 22:31:50 CET 2010
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Tue Nov 23 23:24:19 2010 +0200| [444f32586f6ef937dc8dd66809189fe3fa838f82] | committer: Rémi Denis-Courmont
Win32: fix thread variable leaks
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=444f32586f6ef937dc8dd66809189fe3fa838f82
---
include/vlc_threads.h | 2 +-
src/win32/thread.c | 75 ++++++++++++++++++++++++++++++++++++-------------
2 files changed, 56 insertions(+), 21 deletions(-)
diff --git a/include/vlc_threads.h b/include/vlc_threads.h
index 3770e2f..5bec5c5 100644
--- a/include/vlc_threads.h
+++ b/include/vlc_threads.h
@@ -164,7 +164,7 @@ typedef struct
DWORD writer;
} vlc_rwlock_t;
-typedef DWORD vlc_threadvar_t;
+typedef struct vlc_threadvar *vlc_threadvar_t;
typedef struct vlc_timer *vlc_timer_t;
#endif
diff --git a/src/win32/thread.c b/src/win32/thread.c
index 831c5be..9905652 100644
--- a/src/win32/thread.c
+++ b/src/win32/thread.c
@@ -458,40 +458,74 @@ void vlc_rwlock_unlock (vlc_rwlock_t *lock)
}
/*** Thread-specific variables (TLS) ***/
-int vlc_threadvar_create (vlc_threadvar_t *p_tls, void (*destr) (void *))
+struct vlc_threadvar
{
-#warning FIXME: use destr() callback and stop leaking!
- VLC_UNUSED( destr );
+ DWORD id;
+ void (*destroy) (void *);
+ struct vlc_threadvar *prev;
+ struct vlc_threadvar *next;
+} *vlc_threadvar_last = NULL;
- *p_tls = TlsAlloc();
- return (*p_tls == TLS_OUT_OF_INDEXES) ? EAGAIN : 0;
+int vlc_threadvar_create (vlc_threadvar_t *p_tls, void (*destr) (void *))
+{
+ struct vlc_threadvar *var = malloc (sizeof (*var));
+ if (unlikely(var == NULL))
+ return errno;
+
+ var->id = TlsAlloc();
+ if (var->id == TLS_OUT_OF_INDEXES)
+ return EAGAIN;
+ var->destroy = destr;
+ var->next = NULL;
+ *p_tls = var;
+
+ vlc_mutex_lock (&super_mutex);
+ var->prev = vlc_threadvar_last;
+ vlc_threadvar_last = var;
+ vlc_mutex_unlock (&super_mutex);
+ return 0;
}
void vlc_threadvar_delete (vlc_threadvar_t *p_tls)
{
- TlsFree (*p_tls);
+ struct vlc_threadvar *var = *p_tls;
+
+ vlc_mutex_lock (&super_mutex);
+ if (var->prev != NULL)
+ var->prev->next = var->next;
+ else
+ vlc_threadvar_last = var->next;
+ if (var->next != NULL)
+ var->next->prev = var->prev;
+ vlc_mutex_unlock (&super_mutex);
+
+ TlsFree (var->id);
+ free (var);
}
-/**
- * Sets a thread-local variable.
- * @param key thread-local variable key (created with vlc_threadvar_create())
- * @param value new value for the variable for the calling thread
- * @return 0 on success, a system error code otherwise.
- */
int vlc_threadvar_set (vlc_threadvar_t key, void *value)
{
- return TlsSetValue (key, value) ? ENOMEM : 0;
+ return TlsSetValue (key->id, value) ? ENOMEM : 0;
}
-/**
- * Gets the value of a thread-local variable for the calling thread.
- * This function cannot fail.
- * @return the value associated with the given variable for the calling
- * or NULL if there is no value.
- */
void *vlc_threadvar_get (vlc_threadvar_t key)
{
- return TlsGetValue (key);
+ return TlsGetValue (key->id);
+}
+
+static void vlc_threadvar_cleanup (void)
+{
+ vlc_threadvar_t key;
+
+ /* TODO: use RW lock or something similar */
+ vlc_mutex_lock (&super_mutex);
+ for (key = vlc_threadvar_last; key != NULL; key = key->prev)
+ {
+ void *value = vlc_threadvar_get (key);
+ if (value != NULL)
+ key->destroy (value);
+ }
+ vlc_mutex_unlock (&super_mutex);
}
@@ -524,6 +558,7 @@ static unsigned __stdcall vlc_entry (void *p)
vlc_threadvar_set (cancel_key, &cancel_data);
vlc_sem_post (&entry->ready);
func (data);
+ vlc_threadvar_cleanup ();
return 0;
}
More information about the vlc-commits
mailing list