Forráskód Böngészése

qcacmn: Add delayed work tracking

Add debug tracking to qdf_delayed_work for create and destroy calls.

Change-Id: Ie02c3577acd443e3f252b9b3a47207e5e2d5fe81
CRs-Fixed: 2423645
Dustin Brown 6 éve
szülő
commit
2698eab0b5
2 módosított fájl, 97 hozzáadás és 7 törlés
  1. 38 3
      qdf/inc/qdf_delayed_work.h
  2. 59 4
      qdf/linux/src/qdf_delayed_work.c

+ 38 - 3
qdf/inc/qdf_delayed_work.h

@@ -51,9 +51,13 @@ struct qdf_delayed_work {
  *
  * Return: QDF_STATUS
  */
+#define qdf_delayed_work_create(dwork, callback, context) \
+	__qdf_delayed_work_create(dwork, callback, context, __func__, __LINE__)
+
 qdf_must_check QDF_STATUS
-qdf_delayed_work_create(struct qdf_delayed_work *dwork,
-			qdf_delayed_work_cb callback, void *context);
+__qdf_delayed_work_create(struct qdf_delayed_work *dwork,
+			  qdf_delayed_work_cb callback, void *context,
+			  const char *func, uint32_t line);
 
 /**
  * qdf_delayed_work_destroy() - deinitialize a delayed work @dwork
@@ -61,7 +65,11 @@ qdf_delayed_work_create(struct qdf_delayed_work *dwork,
  *
  * Return: None
  */
-void qdf_delayed_work_destroy(struct qdf_delayed_work *dwork);
+#define qdf_delayed_work_destroy(dwork) \
+	__qdf_delayed_work_destroy(dwork, __func__, __LINE__)
+
+void __qdf_delayed_work_destroy(struct qdf_delayed_work *dwork,
+				const char *func, uint32_t line);
 
 /**
  * qdf_delayed_work_start() - schedule execution of @dwork callback
@@ -83,5 +91,32 @@ bool qdf_delayed_work_start(struct qdf_delayed_work *dwork, uint32_t msec);
  */
 bool qdf_delayed_work_stop_sync(struct qdf_delayed_work *dwork);
 
+#ifdef WLAN_DELAYED_WORK_DEBUG
+/**
+ * qdf_delayed_work_check_for_leaks() - assert no delayed work leaks
+ *
+ * Return: None
+ */
+void qdf_delayed_work_check_for_leaks(void);
+
+/**
+ * qdf_delayed_work_feature_init() - global init logic for delayed work
+ *
+ * Return: None
+ */
+void qdf_delayed_work_feature_init(void);
+
+/**
+ * qdf_delayed_work_feature_deinit() - global de-init logic for delayed work
+ *
+ * Return: None
+ */
+void qdf_delayed_work_feature_deinit(void);
+#else
+static inline void qdf_delayed_work_check_for_leaks(void) { }
+static inline void qdf_delayed_work_feature_init(void) { }
+static inline void qdf_delayed_work_feature_deinit(void) { }
+#endif /* WLAN_DELAYED_WORK_DEBUG */
+
 #endif /* __QDF_DELAYED_WORK_H */
 

+ 59 - 4
qdf/linux/src/qdf_delayed_work.c

@@ -21,6 +21,52 @@
 #include "qdf_trace.h"
 #include "qdf_types.h"
 
+#ifdef WLAN_DELAYED_WORK_DEBUG
+#include "qdf_tracker.h"
+
+#define qdf_dwork_tracker_bits 2 /* 4 buckets */
+static qdf_tracker_declare(qdf_dwork_tracker, qdf_dwork_tracker_bits,
+			   "delayed work leaks", "delayed work create",
+			   "delayed work destroy");
+
+void qdf_delayed_work_feature_init(void)
+{
+	qdf_tracker_init(&qdf_dwork_tracker);
+}
+
+void qdf_delayed_work_feature_deinit(void)
+{
+	qdf_tracker_deinit(&qdf_dwork_tracker);
+}
+
+void qdf_delayed_work_check_for_leaks(void)
+{
+	qdf_tracker_check_for_leaks(&qdf_dwork_tracker);
+}
+
+static inline QDF_STATUS qdf_dwork_dbg_track(struct qdf_delayed_work *dwork,
+					     const char *func, uint32_t line)
+{
+	return qdf_tracker_track(&qdf_dwork_tracker, dwork, func, line);
+}
+
+static inline void qdf_dwork_dbg_untrack(struct qdf_delayed_work *dwork,
+					 const char *func, uint32_t line)
+{
+	qdf_tracker_untrack(&qdf_dwork_tracker, dwork, func, line);
+}
+#else
+static inline QDF_STATUS qdf_dwork_dbg_track(struct qdf_delayed_work *dwork,
+					     const char *func, uint32_t line)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline void qdf_dwork_dbg_untrack(struct qdf_delayed_work *dwork,
+					 const char *func, uint32_t line)
+{ }
+#endif /* WLAN_DELAYED_WORK_DEBUG */
+
 static void __qdf_delayed_work_handler(struct work_struct *work)
 {
 	struct qdf_delayed_work *dwork =
@@ -29,15 +75,22 @@ static void __qdf_delayed_work_handler(struct work_struct *work)
 	dwork->callback(dwork->context);
 }
 
-QDF_STATUS qdf_delayed_work_create(struct qdf_delayed_work *dwork,
-				   qdf_delayed_work_cb callback,
-				   void *context)
+QDF_STATUS __qdf_delayed_work_create(struct qdf_delayed_work *dwork,
+				     qdf_delayed_work_cb callback,
+				     void *context,
+				     const char *func, uint32_t line)
 {
+	QDF_STATUS status;
+
 	QDF_BUG(dwork);
 	QDF_BUG(callback);
 	if (!dwork || !callback)
 		return QDF_STATUS_E_INVAL;
 
+	status = qdf_dwork_dbg_track(dwork, func, line);
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
+
 	INIT_DELAYED_WORK(&dwork->dwork, __qdf_delayed_work_handler);
 	dwork->callback = callback;
 	dwork->context = context;
@@ -45,9 +98,11 @@ QDF_STATUS qdf_delayed_work_create(struct qdf_delayed_work *dwork,
 	return QDF_STATUS_SUCCESS;
 }
 
-void qdf_delayed_work_destroy(struct qdf_delayed_work *dwork)
+void __qdf_delayed_work_destroy(struct qdf_delayed_work *dwork,
+				const char *func, uint32_t line)
 {
 	qdf_delayed_work_stop_sync(dwork);
+	qdf_dwork_dbg_untrack(dwork, func, line);
 }
 
 bool qdf_delayed_work_start(struct qdf_delayed_work *dwork, uint32_t msec)