shithub: openh264

Download patch

ref: eb00d5cb9ed39ffc9501cca82fbcea7218bf01d3
parent: 757a596e97d91a3b55644ce5eca1d8e72e218a1d
author: Sijia Chen <[email protected]>
date: Thu Oct 15 06:11:29 EDT 2015

change std::list to internal implementation and add the new ut file for CWelsCircleQueue
https://rbcommons.com/s/OpenH264/r/1310/

--- a/codec/build/iOS/common/common.xcodeproj/project.pbxproj
+++ b/codec/build/iOS/common/common.xcodeproj/project.pbxproj
@@ -49,6 +49,7 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+		0DB71EF31BAB273500EABC51 /* WelsCircleQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WelsCircleQueue.h; sourceTree = "<group>"; };
 		0DD32A851B467902009181A1 /* WelsThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WelsThread.cpp; sourceTree = "<group>"; };
 		0DD32A871B467911009181A1 /* WelsTaskThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WelsTaskThread.cpp; sourceTree = "<group>"; };
 		0DD32A8E1B467B83009181A1 /* WelsLock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WelsLock.h; sourceTree = "<group>"; };
@@ -145,6 +146,7 @@
 				5BD896B81A7B837700D32B7D /* memory_align.h */,
 				4C3406C118D96EA600DFA14A /* typedefs.h */,
 				5BA8F2BE19603F3500011CE4 /* wels_common_defs.h */,
+				0DB71EF31BAB273500EABC51 /* WelsCircleQueue.h */,
 				0DD32A8E1B467B83009181A1 /* WelsLock.h */,
 				0DD32A8F1B467C73009181A1 /* WelsTask.h */,
 				0DD32A901B467C73009181A1 /* WelsTaskThread.h */,
--- /dev/null
+++ b/codec/common/inc/WelsCircleQueue.h
@@ -1,0 +1,134 @@
+/*!
+ * \copy
+ *     Copyright (c)  2009-2015, Cisco Systems
+ *     All rights reserved.
+ *
+ *     Redistribution and use in source and binary forms, with or without
+ *     modification, are permitted provided that the following conditions
+ *     are met:
+ *
+ *        * Redistributions of source code must retain the above copyright
+ *          notice, this list of conditions and the following disclaimer.
+ *
+ *        * Redistributions in binary form must reproduce the above copyright
+ *          notice, this list of conditions and the following disclaimer in
+ *          the documentation and/or other materials provided with the
+ *          distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *     POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * \file    WelsCircleQueue.h
+ *
+ * \brief   for the queue function needed in ThreadPool
+ *
+ * \date    9/27/2015 Created
+ *
+ *************************************************************************************
+ */
+
+
+#ifndef _WELS_CIRCLE_QUEUE_H_
+#define _WELS_CIRCLE_QUEUE_H_
+
+#include "typedefs.h"
+
+namespace WelsCommon {
+
+template<typename TNodeType>
+class CWelsCircleQueue {
+ public:
+  CWelsCircleQueue() {
+    m_iMaxNodeCount = 50;
+    m_pCurrentQueue = static_cast<TNodeType**> (malloc (m_iMaxNodeCount * sizeof (TNodeType*)));
+    //here using array to simulate list is to avoid the frequent malloc/free of Nodes which may cause fragmented memory
+    m_iCurrentListStart = m_iCurrentListEnd = 0;
+  };
+  ~CWelsCircleQueue() {
+    free (m_pCurrentQueue);
+  };
+
+  int32_t size() {
+    return ((m_iCurrentListEnd >= m_iCurrentListStart)
+            ? (m_iCurrentListEnd - m_iCurrentListStart)
+            : (m_iMaxNodeCount - m_iCurrentListStart + m_iCurrentListEnd));
+  }
+
+  int32_t push_back (TNodeType* pNode) {
+    m_pCurrentQueue[m_iCurrentListEnd] = pNode;
+    m_iCurrentListEnd ++;
+
+    if (m_iCurrentListEnd == m_iMaxNodeCount) {
+      m_iCurrentListEnd = 0;
+    }
+    if (m_iCurrentListEnd == m_iCurrentListStart) {
+      int32_t ret = ExpandList();
+      if (ret) {
+        return 1;
+      }
+    }
+    return 0;
+  }
+
+  void pop_front() {
+    if (size() > 0) {
+      m_pCurrentQueue[m_iCurrentListStart] = NULL;
+      m_iCurrentListStart = ((m_iCurrentListStart < (m_iMaxNodeCount - 1))
+                             ? (m_iCurrentListStart + 1)
+                             : 0);
+    }
+  }
+
+  TNodeType* begin() {
+    return m_pCurrentQueue[m_iCurrentListStart];
+  }
+ private:
+  int32_t ExpandList() {
+    TNodeType** tmpCurrentTaskQueue = static_cast<TNodeType**> (malloc (m_iMaxNodeCount * 2 * sizeof (TNodeType*)));
+    if (tmpCurrentTaskQueue == NULL) {
+      return 1;
+    }
+
+    memcpy (tmpCurrentTaskQueue,
+            (m_pCurrentQueue + m_iCurrentListStart),
+            (m_iMaxNodeCount - m_iCurrentListStart)*sizeof (TNodeType*));
+    if (m_iCurrentListEnd > 0) {
+      memcpy (tmpCurrentTaskQueue + m_iMaxNodeCount - m_iCurrentListStart,
+              m_pCurrentQueue,
+              m_iCurrentListEnd * sizeof (TNodeType*));
+    }
+
+    free (m_pCurrentQueue);
+
+    m_pCurrentQueue = tmpCurrentTaskQueue;
+    m_iCurrentListEnd = m_iMaxNodeCount;
+    m_iCurrentListStart = 0;
+    m_iMaxNodeCount = m_iMaxNodeCount * 2;
+
+    return 0;
+  }
+  int32_t m_iCurrentListStart;
+  int32_t m_iCurrentListEnd;
+  int32_t m_iMaxNodeCount;
+  TNodeType** m_pCurrentQueue;
+};
+
+
+}
+
+
+#endif
+
+
+
--- a/codec/common/inc/WelsThreadPool.h
+++ b/codec/common/inc/WelsThreadPool.h
@@ -43,9 +43,10 @@
 #define _WELS_THREAD_POOL_H_
 
 #include <map>
-
+#include <stdio.h>
 #include "WelsTask.h"
 #include "WelsTaskThread.h"
+#include "WelsCircleQueue.h"
 
 namespace WelsCommon {
 
@@ -55,7 +56,6 @@
   virtual WELS_THREAD_ERROR_CODE OnTaskCancelled (IWelsTask* pTask) = 0;
 };
 
-
 class  CWelsThreadPool : public CWelsThread, public IWelsTaskThreadSink {
  public:
   enum {
@@ -96,7 +96,8 @@
 
  private:
   int32_t   m_iMaxThreadNum;
-  std::list<IWelsTask*>    m_cWaitedTasks;
+  //std::list<IWelsTask*>    m_cWaitedTasks;
+  CWelsCircleQueue<IWelsTask>* m_cWaitedTasks;
   std::map<uintptr_t, CWelsTaskThread*>  m_cIdleThreads;
   std::map<uintptr_t, CWelsTaskThread*>  m_cBusyThreads;
   IWelsThreadPoolSink*   m_pSink;
--- a/codec/common/src/WelsThreadPool.cpp
+++ b/codec/common/src/WelsThreadPool.cpp
@@ -50,6 +50,7 @@
 
 CWelsThreadPool::CWelsThreadPool (IWelsThreadPoolSink* pSink, int32_t iMaxThreadNum) :
   m_pSink (pSink) {
+  m_cWaitedTasks = new CWelsCircleQueue<IWelsTask>();
   m_iMaxThreadNum = 0;
 
   Init (iMaxThreadNum);
@@ -58,6 +59,8 @@
 
 CWelsThreadPool::~CWelsThreadPool() {
   Uninit();
+
+  delete m_cWaitedTasks;
 }
 
 WELS_THREAD_ERROR_CODE CWelsThreadPool::OnTaskStart (CWelsTaskThread* pThread, IWelsTask* pTask) {
@@ -239,7 +242,7 @@
 void  CWelsThreadPool::AddTaskToWaitedList (IWelsTask* pTask) {
   CWelsAutoLock  cLock (m_cLockWaitedTasks);
 
-  m_cWaitedTasks.push_back (pTask);
+  m_cWaitedTasks->push_back (pTask);
   return;
 }
 
@@ -267,20 +270,18 @@
 }
 
 int32_t  CWelsThreadPool::GetWaitedTaskNum() {
-  return static_cast<int32_t> (m_cWaitedTasks.size());
+  return m_cWaitedTasks->size();
 }
 
 IWelsTask* CWelsThreadPool::GetWaitedTask() {
   CWelsAutoLock lock (m_cLockWaitedTasks);
-
-  if (m_cWaitedTasks.size() == 0) {
+  if (m_cWaitedTasks->size() == 0) {
     return NULL;
   }
 
-  std::list<IWelsTask*>::iterator it = m_cWaitedTasks.begin();
-  IWelsTask* pTask = *it;
+  IWelsTask* pTask = m_cWaitedTasks->begin();
 
-  m_cWaitedTasks.pop_front();
+  m_cWaitedTasks->pop_front();
 
   return pTask;
 }
@@ -287,17 +288,12 @@
 
 void  CWelsThreadPool::ClearWaitedTasks() {
   CWelsAutoLock cLock (m_cLockWaitedTasks);
-
-  std::list<IWelsTask*>::iterator iter = m_cWaitedTasks.begin();
-
   if (m_pSink) {
-    while (iter != m_cWaitedTasks.end()) {
-      m_pSink->OnTaskCancelled (*iter);
-      ++ iter;
+    while (0 != m_cWaitedTasks->size()) {
+      m_pSink->OnTaskCancelled (m_cWaitedTasks->begin());
+      m_cWaitedTasks->pop_front();
     }
   }
-
-  m_cWaitedTasks.clear();
 }
 
 }
--- /dev/null
+++ b/test/common/CWelsCircleQueue.cpp
@@ -1,0 +1,83 @@
+#include <gtest/gtest.h>
+#include "WelsCircleQueue.h"
+#include "WelsTask.h"
+
+using namespace WelsCommon;
+
+TEST (CWelsCircleQueue, CWelsCircleQueueOne) {
+  CWelsCircleQueue<IWelsTask> cTaskList;
+  IWelsTask* pTask = NULL;
+
+  for (int i = 0; i < 60; i++) {
+    cTaskList.push_back (pTask);
+    EXPECT_TRUE (1 == cTaskList.size()) << "after push size=" << cTaskList.size() ;
+
+    cTaskList.pop_front();
+    EXPECT_TRUE (0 == cTaskList.size()) << "after pop size=" << cTaskList.size() ;
+  }
+}
+
+TEST (CWelsCircleQueue, CWelsCircleQueueTen) {
+  CWelsCircleQueue<IWelsTask> cTaskList;
+  IWelsTask* pTask = NULL;
+
+  for (int j = 0; j < 10; j++) {
+
+    for (int i = 0; i < 10; i++) {
+      EXPECT_TRUE (i == cTaskList.size()) << "before push size=" << cTaskList.size() ;
+      cTaskList.push_back (pTask);
+    }
+    EXPECT_TRUE (10 == cTaskList.size()) << "after push size=" << cTaskList.size() ;
+
+
+    for (int i = 9; i >= 0; i--) {
+      cTaskList.pop_front();
+      EXPECT_TRUE (i == cTaskList.size()) << "after pop size=" << cTaskList.size() ;
+    }
+  }
+}
+
+TEST (CWelsCircleQueue, CWelsCircleQueueExpand) {
+  CWelsCircleQueue<IWelsTask> cTaskList;
+  IWelsTask* pTask = NULL;
+
+  const int kiIncreaseNum = (rand() % 65535) + 1;
+  const int kiDecreaseNum = rand() % kiIncreaseNum;
+
+  for (int j = 0; j < 10; j++) {
+
+    for (int i = 0; i < kiIncreaseNum; i++) {
+      cTaskList.push_back (pTask);
+    }
+    EXPECT_TRUE (kiIncreaseNum + j * (kiIncreaseNum - kiDecreaseNum) == cTaskList.size()) << "after push size=" <<
+        cTaskList.size() ;
+
+    for (int i = kiDecreaseNum; i > 0; i--) {
+      cTaskList.pop_front();
+    }
+    EXPECT_TRUE ((j + 1) * (kiIncreaseNum - kiDecreaseNum) == cTaskList.size()) << "after pop size=" << cTaskList.size() ;
+  }
+}
+
+TEST (CWelsCircleQueue, CWelsCircleQueueOverPop) {
+  CWelsCircleQueue<IWelsTask> cTaskList;
+  IWelsTask* pTask = NULL;
+
+  const int kiDecreaseNum = (rand() % 65535) + 1;
+  const int kiIncreaseNum = rand() % kiDecreaseNum;
+
+  EXPECT_TRUE (0 == cTaskList.size());
+  cTaskList.pop_front();
+  EXPECT_TRUE (0 == cTaskList.size());
+
+  for (int i = 0; i < kiIncreaseNum; i++) {
+    cTaskList.push_back (pTask);
+  }
+
+  for (int i = kiDecreaseNum; i > 0; i--) {
+    cTaskList.pop_front();
+  }
+
+  EXPECT_TRUE (0 == cTaskList.size());
+}
+
--- a/test/common/targets.mk
+++ b/test/common/targets.mk
@@ -1,6 +1,7 @@
 COMMON_UNITTEST_SRCDIR=test/common
 COMMON_UNITTEST_CPP_SRCS=\
 	$(COMMON_UNITTEST_SRCDIR)/ExpandPicture.cpp\
+	$(COMMON_UNITTEST_SRCDIR)/CWelsCircleQueue.cpp\
 
 COMMON_UNITTEST_OBJS += $(COMMON_UNITTEST_CPP_SRCS:.cpp=.$(OBJ))