VxWorks6.6移植嵌入式ICE中間件解決方案


一、前言

         iceE1.3.0中間件當前版本並沒有直接支持VxWorks,我們可能在百度搜索上也找不到相關移植資料。在Windows,unix,linux等相關操作系統下,也許你可以輕鬆地搞定。或許估計你曾經嘗試把它移植到VxWorks實時操作系統,其過程估計沒有想象那麼容易,只有身臨其中才能有所體驗了。

         在Ice移植VxWorks過程中,我們需要定義宏“VXWORKS”開關。VxWorks底層網絡遵循POSIX標準,但不同的操作系統中POSIX還是有一點差異,代碼修改過程中使用VXWORKS標誌區別出來。

         本文基於VxWorks本身的仿真器實現,完成ice的動態庫創建,並使用最簡單的例子“Hello World!”實現客服與服務器之間的通信。

讓我們開始進入正式的主題吧!

二、瞭解POISX標準

        POSIX具有多重含義,通常指POSIX標準,該標準是一個可移植操作系統接口(Portable OperatingSystem Interface),由IEEE提出,ANSI和ISO將其標準化。POSIX的目的是使應用程序源代碼可以在兼容POSIX的操作系統上移植。理想的目標是應用程序移植到另一個操作系統只需要重新編譯就可以運行。POSIX最後一個字母“X”表達了這種超乎操作系統差異的理想。目前並沒有實現這種理想:從操作系統看,由於目標、要求、理念、條件的差異,並不是所有的操作系統都實現100%POSIX兼容;從應用程序看,很多代碼編寫使用了特定操作系統支持的調用,並沒有很好地使用POSIX接口。但是,很顯然,使用POSIX接口的應用程序在兼容POSIX的操作系統間移植將是很輕鬆的事情。

        POSIX標準是一個處於不斷髮展之中的龐大體系,包括:

1003.1       系統API

1003.2       SHELL及工具

1003.3       POSIX符合性測試方法

1003.5      ADA語言接口

1003.13      標準化可移植實時應用環境AEP

        其中,POSIX 1003.1系列標準是POSIX最主體內容,也是我們最關心的部分。該系列內容由如下主體定義以及一些擴展和增補組成:

1003.1       1988年通過,基本OS接口

1003.1b     1993年通過,實時擴展

1003.1c      1995年通過,線程擴展

1003.1d     1999年通過,實時擴展

1003.1j      2000年通過,高級實時擴展

1003.1q     2000年通過,事件數據流跟蹤

三、測試POISX線程相關的函數


圖3.1 創建RTP工程


圖3.2 選擇編譯器

1、編寫一個測試代碼testpoisx.cpp

#include <stdio.h>

#include <pthread.h>

#include <errno.h>

#include <semLib.h>

 

typedef void* (*LPFUNCPTR)(void*);

   

struct counter

{

    int i;

    int j;

};

 

static bool __running =true;

static counter __counter = { 0, 0 };

pthread_mutex_t __mutex;

 

static void*

task1(void* arg)

{

    struct timespec ts;

   while(__running)

    {

       int rc = pthread_mutex_lock(&__mutex);          

       printf("Currentcounter i:%d\n", __counter.i++);       

       rc =pthread_mutex_unlock(&__mutex);       

  

       ts.tv_sec = 1;

       ts.tv_nsec = 0;

       nanosleep(&ts, 0);

    }

   return 0;

}

 

static void*

task2(void* arg)

{

    struct timespec ts;

   while(__running)

    {

       int rc = pthread_mutex_lock(&__mutex);          

       printf("Currentcounter j:%d\n", __counter.j++);       

       rc =pthread_mutex_unlock(&__mutex);       

       ts.tv_sec = 2;

       ts.tv_nsec = 0;

       nanosleep(&ts, 0);

    }

   return 0;

}

 

int

startTask(LPFUNCPTR func,

          size_t stackSize,

          const bool& realtimeScheduling,

          const int& priority)

{

    pthread_tid;

   pthread_attr_t attr;

    int rc = pthread_attr_init(&attr);

    if (rc != 0)

    {

        return -1;

    }

    if (stackSize > 0)

    {

        if(stackSize < PTHREAD_STACK_MIN)

        {

           stackSize = PTHREAD_STACK_MIN;

        }

        rc= pthread_attr_setstacksize(&attr, stackSize);

        if (rc != 0)

        {

           return -1;

        }

    }

 

    if (realtimeScheduling)

    {

        rc= pthread_attr_setschedpolicy(&attr, SCHED_RR);

        if (rc != 0)

        {

           return -1;

        }

       sched_param param;

       param.sched_priority = priority;

        rc= pthread_attr_setschedparam(&attr, &param);

        if (rc != 0)

        {

            return -1;

        }

       pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);

    }

    rc =pthread_create(&id, &attr, func, NULL);

    if (rc != 0)

    {

        return -1;

    }

    return id;

}

 

int

stopTask(constpthread_t& id)

{

    int rc = pthread_detach(id);

    return rc;

}

 

int

main(int argc, char* argv[])

{      

    int rc = pthread_mutex_init(&__mutex, 0);

    if (rc != 0)

    {

        return -1;

    }

    int nId1 = startTask((LPFUNCPTR)task1, 4096,true, 100);

    int nId2 = startTask((LPFUNCPTR)task2, 4096,true, 100);

   

    while (__running)

    {

        if (getchar() == '\n')

        {

            __running= false;

            break;

        }

    }

    struct timespec ts;

    ts.tv_sec= 2;

    ts.tv_nsec= 0;

    nanosleep(&ts,0);

   

    if (nId1 > 0)

    {

       stopTask(nId1);

    }

    if (nId2 > 0)

    {

       stopTask(nId2);

    }

   

    rc =pthread_mutex_destroy(&__mutex);

    if (rc != 0)

    {

        return -1;

    }

    return 0;

}

2、運行測試代碼


圖3.3 選擇vxsim0仿真


圖3.4 運行之後的結果

當程序代碼執行pthread_create時,返回結果始終爲“-1”,這裏你必須對VxWorks的POSIX過程要熟悉了。經過查詢有關錯誤代碼資料(#define        ENOSYS             71              /*Function not implemented */),我們發現VxWorks提供的仿真器功能很基礎,但有很多組件未包含進來,於是我們需要定製自己的鏡像文件,詳細過程參考圖5.8-5.9。


圖3.5 兩條任務線程啓動

Current counter i:0

Current counter j:0

Current counter i:1

Current counter j:1

Current counter i:2

Current counter i:3

Current counter j:2

Current counter i:4

Current counter i:5

Current counter j:3

Current counter i:6

Current counter i:7

Current counter j:4

Current counter i:8

Current counter i:9

Current counter j:5

Current counter i:10

。。。

四、創建X86鏡像文件


圖4.1 創建VxWorks鏡像文件

 


圖4.2 工程名稱爲vxworks_i386

 

圖4.3 選擇BSP和編譯器

 

圖4.4 該選擇默認


圖4.5 選擇PROFILE_DEVELOPMENT

         如圖4.5所示,我們選擇“PROFILE_DEVELOPMENT”主要後面用到剪裁包含的組件,具體怎麼操作,後面將會講到。


圖4.6 完成嚮導


圖4.7 鏡像文件樹型結構

我們打開usrAppInit.c文件,添加一句簡單的啓動信息,最後編譯鏡像工程

/******************************************************************************

*

* usrAppInit - initialize theusers application

*/

 

voidusrAppInit (void)

    {

#ifdefUSER_APPL_INIT

    USER_APPL_INIT;     /* for backwards compatibility */

#endif

 

    /* addapplication specific code here */

    printf("Hello World!\n");

    }       

五、創建新連接


圖5.1 新建一個仿真連接


圖5.2 選擇上述生成的鏡像文件

 

圖5.3 定製內存大小,此項默認即可


圖5.4 優先級爲belowNormal

 

圖5.5 設置目標服務選擇


圖5.6 設置路徑對象映射關係

 

圖5.7 完成嚮導


圖5.8 剪裁包含POSIX線程調度組件

 

圖5.9有效的POSIX線程組件


圖5.10 啓動連接vxsim2

六、創建libice130動態連接庫

        如何創建動態連接庫及使用調用,參考之前《VxWorks6.6開發共享庫指南要點》文檔,然後工程注意事項如下:

        編譯開關需要增加“-DVXWORKS -D__i386 -DICE_API_EXPORTS-Xrtti”


圖6.1 編譯選項

七、修改libice130源碼

         這部分工作相對來說比較大,也是決定移植成功的關鍵階段。總共按照8個方面修改,主要是適應VxWorks開發環境而配置的內容。

1、修改include/IceE/Cond.h文件

    #ifdef VXWORKS

       Time tm = Time::now() + timeout;

       timeval tv = tm.gettimeval();

#else

       timeval tv = Time::now() + timeout;

#endif

2、修改include/IceE/Mutex.h文件

1)增加包含文件

#ifdef VXWORKS

#include<semLib.h>

#endif

2)修改Mutex::init(…)函數

inline void

Mutex::init(MutexProtocol protocol)

{

#if defined(__linux) &&!defined(__USE_UNIX98)

#  ifdef NDEBUG

   int rc = pthread_mutex_init(&_mutex, 0);

#  else

   pthread_mutexattr_t attr = { PTHREAD_MUTEX_ERRORCHECK_NP };

   int rc = pthread_mutex_init(&_mutex, &attr);

#  endif

   if(rc != 0)

   {

        throw ThreadSyscallException(__FILE__,__LINE__, rc);

   }

#elifdefined(VXWORKS)

    //memset(&_mutex, '\0',sizeof(_mutex));

    int rc = pthread_mutex_init(&_mutex,0);

    assert(rc == 0);

    if (rc != 0)

    {

        throw ThreadSyscallException(__FILE__,__LINE__, rc);

    }

#else // !defined(__linux) || defined(__USE_UNIX98)

   pthread_mutexattr_t attr;

   int rc = pthread_mutexattr_init(&attr);

   assert(rc == 0);

   if(rc != 0)

   {

        throw ThreadSyscallException(__FILE__,__LINE__, rc);

   }

 

   //

   // Enable mutex error checking in debug builds

   //

#ifndef NDEBUG

   rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);

   assert(rc == 0);

   if(rc != 0)

   {

        throw ThreadSyscallException(__FILE__,__LINE__, rc);

   }

#endif

 

   //

   // If system has support for priority inheritance we set the protocol

   // attribute of the mutex

   //

#ifdefined(_POSIX_THREAD_PRIO_INHERIT) && _POSIX_THREAD_PRIO_INHERIT >0

   if(PrioInherit == protocol)

   {

        rc =pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);

        if(rc != 0)

        {

            throwThreadSyscallException(__FILE__, __LINE__, rc);

        }

   }

#endif

 

   rc = pthread_mutex_init(&_mutex, &attr);

   assert(rc == 0);

   if(rc != 0)

   {

        throw ThreadSyscallException(__FILE__,__LINE__, rc);

   }

 

   rc = pthread_mutexattr_destroy(&attr);

   assert(rc == 0);

   if(rc != 0)

   {

        throw ThreadSyscallException(__FILE__,__LINE__, rc);

   }

#endif

}

3)、修改include/IceE/NetWork.h文件

#ifdef _WIN32

#  include <winsock2.h>

typedef int ssize_t;

#else

#  include <unistd.h>

#  include <fcntl.h>

#  include <sys/socket.h>

#  if defined(__hpux)

#      include <sys/time.h>

#  else

#ifndef VXWORKS

#      include <sys/poll.h>

#endif

#      include <sys/time.h>

#  endif

3、修改include/IceE/Time.h文件

1)增加下面包含文件

#ifndef_WIN32_WCE

#   if defined(_WIN32)

#       include <sys/timeb.h>

#       include <time.h>

#   else

#       include <sys/time.h>

#   endif

#endif

2)修改Time類

#ifndef _WIN32

#ifdef VXWORKS

    timeval gettimeval() const;

#else

    operator timeval()const;

#endif

#endif

4、修改src/IceE/Instance.cpp文件

#ifdef _WIN32

#  include <winsock2.h>

#  ifndef _WIN32_WCE

#      include <process.h>

#  endif

#else

#  include <signal.h>

#ifndef VXWORKS

#  include <pwd.h>

#endif

#  include <sys/types.h>

#endif

 

using namespace std;

using namespace Ice;

using namespace IceInternal;

if(!newUser.empty())

                {

#ifndef VXWORKS                               

                    struct passwd* pw =getpwnam(newUser.c_str());

                    if(!pw)

                    {

                        SyscallExceptionex(__FILE__, __LINE__);

                        ex.error =getSystemErrno();

                        throw ex;

                    }

 

                    if(setgid(pw->pw_gid) ==-1)

                    {

                        SyscallExceptionex(__FILE__, __LINE__);

                        ex.error =getSystemErrno();

                        throw ex;

                    }

 

                    if(setuid(pw->pw_uid) ==-1)

                    {

                        SyscallExceptionex(__FILE__, __LINE__);

                        ex.error =getSystemErrno();

                        throw ex;

                    }

#endif

 

5、修改src/IceE/NetWork.cpp文件

1)修改包含文件

# include <sys/ioctl.h>

# include <net/if.h>

#ifdef VXWORKS

#   include <ioLib.h>

#   include <sockLib.h>

#define socklen_tint

#endif

# ifdef __sun

#   include <sys/sockio.h>

# endif

#endif

2)修改setBlock(…)函數

void

IceInternal::setBlock(SOCKET fd,bool block)

{

   if(block)

   {

#ifdef _WIN32

        unsigned long arg = 0;

        if(ioctlsocket(fd, FIONBIO, &arg)== SOCKET_ERROR)

        {

            closeSocketNoThrow(fd);

            SocketException ex(__FILE__, __LINE__);

            ex.error = WSAGetLastError();

            throw ex;

        }

#elif VXWORKS

        unsigned long lNonBlock = 0;

        if (ioctl(fd, FIONBIO, &lNonBlock)== SOCKET_ERROR)

        {

                 closeSocketNoThrow(fd);

                 SocketExceptionex(__FILE__, __LINE__);

                 ex.error= errno;

                 throwex;

        }

#else

        int flags = fcntl(fd, F_GETFL);

        flags &= ~O_NONBLOCK;

        if(fcntl(fd, F_SETFL, flags) ==SOCKET_ERROR)

        {

            closeSocketNoThrow(fd);

            SocketException ex(__FILE__,__LINE__);

            ex.error = errno;

            throw ex;

        }

#endif

   }

   else

   {

#ifdef _WIN32

        unsigned long arg = 1;

        if(ioctlsocket(fd, FIONBIO, &arg)== SOCKET_ERROR)

       {

            closeSocketNoThrow(fd);

            SocketException ex(__FILE__,__LINE__);

            ex.error = WSAGetLastError();

            throw ex;

        }

#elif VXWORKS

        unsigned long lNonBlock = 1;

        if (ioctl(fd, FIONBIO, &lNonBlock)== SOCKET_ERROR)

        {

                 closeSocketNoThrow(fd);

                 SocketExceptionex(__FILE__, __LINE__);

                 ex.error= errno;

                 throwex;

        }

#else

        int flags = fcntl(fd, F_GETFL);

        flags |= O_NONBLOCK;

        if(fcntl(fd, F_SETFL, flags) ==SOCKET_ERROR)

        {

            closeSocketNoThrow(fd);

            SocketException ex(__FILE__,__LINE__);

            ex.error = errno;

            throw ex;

        }

#endif

   }

}

3)修改createPipe (…)函數

void

IceInternal::createPipe(SOCKETfds[2])

{

#ifdef _WIN32

 

   SOCKET fd = createSocket();

   setBlock(fd, true);

 

   struct sockaddr_in addr;

   memset(&addr, 0, sizeof(addr));

 

   struct sockaddr_in* addrin = reinterpret_cast<structsockaddr_in*>(&addr);

   addrin->sin_family = AF_INET;

   addrin->sin_port = htons(0);

   addrin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);

 

   doBind(fd, addr);

   doListen(fd, 1);

 

   try

   {

        fds[0] = createSocket();

   }

   catch(...)

   {

        ::closesocket(fd);

        throw;

   }

 

   try

   {

        setBlock(fds[0], true);

#ifndef NDEBUG

        bool connected = doConnect(fds[0],addr);

        assert(connected);

#else

        doConnect(fds[0], addr);

#endif

   }

   catch(...)

   {

        // fds[0] is closed by doConnect

        ::closesocket(fd);

        throw;

   }

 

   try

   {

        fds[1] = doAccept(fd);

   }

   catch(...)

   {

        ::closesocket(fds[0]);

        ::closesocket(fd);

        throw;

   }

 

   ::closesocket(fd);

 

   try

    {

        setBlock(fds[1], true);

   }

   catch(...)

   {

        ::closesocket(fds[0]);

        // fds[1] is closed by setBlock

        throw;

   }

#elifdefined(VXWORKS)

 

    SOCKET fd = createSocket();

    setBlock(fd, true);

 

    struct sockaddr_in addr;

    memset(&addr, 0, sizeof(addr));

 

    struct sockaddr_in* addrin =reinterpret_cast<struct sockaddr_in*>(&addr);

    addrin->sin_family = AF_INET;

    addrin->sin_port = htons(0);

    addrin->sin_addr.s_addr =htonl(INADDR_LOOPBACK);

 

    doBind(fd, addr);

    doListen(fd, 1);

 

    try

    {

        fds[0] = createSocket();

    }

    catch(...)

    {

        ::close(fd);

        throw;

    }

 

    try

    {

        setBlock(fds[0], true);

#ifndef NDEBUG

        bool connected = doConnect(fds[0],addr);

        assert(connected);

#else

        doConnect(fds[0], addr);

#endif

    }

    catch(...)

    {

        // fds[0] is closed by doConnect

        ::close(fd);

        throw;

    }

 

    try

    {

        fds[1] = doAccept(fd);

    }

    catch(...)

    {

        ::close(fds[0]);

        ::close(fd);

        throw;

    }

 

    ::close(fd);

 

    try

    {

        setBlock(fds[1], true);

    }

    catch(...)

    {

        ::close(fds[0]);

        // fds[1] is closed by setBlock

        throw;

    }

#else

 

   if(::pipe(fds) != 0)

   {

        SyscallException ex(__FILE__,__LINE__);

        ex.error = getSystemErrno();

        throw ex;

   }

 

   try

   {

        setBlock(fds[0], true);

   }

   catch(...)

   {

        // fds[0] is closed by setBlock

        closeSocketNoThrow(fds[1]);

        throw;

   }

 

   try

   {

        setBlock(fds[1], true);

   }

   catch(...)

   {

        closeSocketNoThrow(fds[0]);

        // fds[1] is closed by setBlock

        throw;

   }

 

#endif

}

6、修改src/IceE/Selector.h文件

1)修改包含文件與宏定義

#if defined(__linux) &&!defined(ICE_NO_EPOLL)

#  define ICE_USE_EPOLL 1

#elif defined(__APPLE__) &&!defined(ICE_NO_KQUEUE)

#  define ICE_USE_KQUEUE 1

#elif defined(_WIN32)

#  define ICE_USE_SELECT 1

#elif  defined(VXWORKS)

#   define ICE_USE_SELECT 1

#endif

 

#if defined(ICE_USE_EPOLL)

#ifndef VXWORKS

#  include <sys/epoll.h>

#endif

#elif defined(ICE_USE_KQUEUE)

#  include <sys/event.h>

#else

#  if !defined(ICE_USE_SELECT)

#ifndef VXWORKS

#     include <sys/poll.h>

#endif

#  endif

#  include <list>

#endif

 

#ifdef VXWORKS

#   include <strings.h>

#endif

#include<IceE/NormalUtil.h>

2)修改函數select(…)

int select()

   {

       while(true)

       {

            int ret;

            _nSelectedReturned = 0;

            _nSelected = 0;

#if defined(ICE_USE_EPOLL)

            ret = epoll_wait(_queueFd,&_events[0], _events.size(), _timeout > 0 ? _timeout * 1000 : -1);

#elif defined(ICE_USE_KQUEUE)

            assert(!_events.empty());

            if(_timeout > 0)

            {

                struct timespec ts;

                ts.tv_sec = _timeout;

                ts.tv_nsec = 0;

                ret = kevent(_queueFd, 0, 0,&_events[0], _events.size(), &ts);

            }

            else

            {

                ret = kevent(_queueFd, 0, 0,&_events[0], _events.size(), 0);

            }

#elif defined(ICE_USE_SELECT)

            fd_set* rFdSet =fdSetCopy(_selectedReadFdSet, _readFdSet);

            fd_set* wFdSet =fdSetCopy(_selectedWriteFdSet, _writeFdSet);

            fd_set* eFdSet =fdSetCopy(_selectedErrorFdSet, _errorFdSet);

            int nFd = 0;

#ifndef WIN32

            nFd = FD_SETSIZE;     

#endif           

            if(_timeout > 0)

            {

                struct timeval tv;

                tv.tv_sec = _timeout;

                tv.tv_usec = 0;

                ret = ::select(nFd, rFdSet, wFdSet, eFdSet, &tv); // The firstparameter is ignored on Windows

            }

            else

            {

                ret = ::select(nFd, rFdSet, wFdSet, eFdSet, 0); // The firstparameter is ignored on Windows

            }

#else

            ret = poll(&_pollFdSet[0], _pollFdSet.size(),_timeout > 0 ? _timeout * 1000 : -1);

#endif

            if(ret == SOCKET_ERROR)

            {

                if(interrupted())

                {

                    continue;

                }

 

                assert(false);

                Ice::SocketException ex(__FILE__, __LINE__);

                ex.error = getSocketErrno();

                throw ex;

            }

 

            assert(ret >= 0);

            _nSelected =static_cast<unsigned int>(ret);

            if(_nSelected == 0)

           {

                assert(_timeout > 0);

                _timeout = 0;

            }

            return _nSelected;

       }

}

3)修改函數getNextSelected (…)函數

 T* getNextSelected()

   {

       assert(_nSelected > 0);

 

#if defined(ICE_USE_EPOLL) ||defined(ICE_USE_KQUEUE)

       if(_nSelectedReturned == _nSelected)

       {

            if(_count != _events.size())

            {

               _events.resize(_count);

            }

            return 0;

       }

 

       //

       // Round robin for the filedescriptors.

       //

       T* larger = 0;

       T* smallest = 0;

       for(unsigned int i = 0; i < _nSelected; ++i)

        {

#if defined(ICE_USE_EPOLL)

            T* handler =reinterpret_cast<T*>(_events[i].data.ptr);

#else

            T* handler =reinterpret_cast<T*>(_events[i].udata);

#endif

            if(!handler) // _fdIntrRead

            {

                assert(_nSelectedReturned >0 && _interruptCount == 0);

                continue;

            }

 

            if(handler->_fd > _lastFd&& (larger == 0 || handler->_fd < larger->_fd))

            {

                larger = handler;

            }

 

            if(smallest == 0 || handler->_fd< smallest->_fd)

            {

                smallest = handler;

            }

       }

 

       ++_nSelectedReturned;

       if(larger)

       {

            _lastFd = larger->_fd;

            return larger;

       }

       else

       {

            assert(smallest);

            _lastFd = smallest->_fd;

            return smallest;

       }

#else

       if(_nSelectedReturned == _nSelected)

       {

            return 0;

       }

 

       //

       // Round robin for the filedescriptors.

       //

       SOCKET largerFd = INVALID_SOCKET;

       SOCKET smallestFd = INVALID_SOCKET;

#if defined(ICE_USE_SELECT)

#ifdef VXWORKS

        int nFdsetMaxCount =howmany(FD_SETSIZE, NFDBITS);

        int nReadFdSetCount = 0;

        int nWriteFdSetCount = 0;

        int nErrorFdSetCount = 0;

        for (int j = 0; j < nFdsetMaxCount;++j)

        {

                 intnCount1 = IceUtil::getFdsetBits(_selectedReadFdSet.fds_bits[j]);

                 nReadFdSetCount+= nCount1;

                

                 int nCount2 =IceUtil::getFdsetBits(_selectedWriteFdSet.fds_bits[j]);

                 nWriteFdSetCount+= nCount2;

                                 

                 intnCount3 = IceUtil::getFdsetBits(_selectedErrorFdSet.fds_bits[j]);

                 nErrorFdSetCount+= nCount3;

        }

       

        if (nReadFdSetCount == 0 &&nWriteFdSetCount == 0 && nErrorFdSetCount == 0)

        {

            Ice::Errorout(_instance->initializationData().logger);

            out << "select() inselector returned " << _nSelected << " but no filedescriptoris ready";

            return 0;

        }

        int nfdSetCount = 0;              

        const fd_set* fdSet;

        if (_nSelectedReturned <nReadFdSetCount)

        {

            fdSet = &_selectedReadFdSet;

            nfdSetCount = nReadFdSetCount;

        }

        else if (_nSelectedReturned <nWriteFdSetCount + nReadFdSetCount)

        {

            fdSet = &_selectedWriteFdSet;

            nfdSetCount = nWriteFdSetCount;

        }

        else

        {

            fdSet = &_selectedErrorFdSet;

            nfdSetCount = nErrorFdSetCount;

        }

      

        for (u_short i = 0; i < FD_SETSIZE;++i)

        {

            if (!FD_ISSET(i, fdSet))

            {

                continue;

            }

            SOCKET fd = i;

#else

       if(_selectedReadFdSet.fd_count == 0 &&_selectedWriteFdSet.fd_count == 0 && _selectedErrorFdSet.fd_count == 0)

       {

            Ice::Errorout(_instance->initializationData().logger);

            out << "select() inselector returned " << _nSelected << " but nofiledescriptor is ready";

            return 0;

       }

 

       const fd_set* fdSet;

       if(_nSelectedReturned < _selectedReadFdSet.fd_count)

       {

            fdSet = &_selectedReadFdSet;

       }

       else if(_nSelectedReturned < _selectedWriteFdSet.fd_count +_selectedReadFdSet.fd_count)

       {

            fdSet = &_selectedWriteFdSet;

       }

       else

       {

            fdSet = &_selectedErrorFdSet;

       }

       for(u_short i = 0; i < fdSet->fd_count; ++i)

       {

           SOCKET fd = fdSet->fd_array[i];

#endif

#else

       for(std::vector<struct pollfd>::const_iterator p =_pollFdSet.begin(); p != _pollFdSet.end(); ++p)

       {

            if(p->revents == 0)

            {

                continue;

            }

            SOCKET fd = p->fd;

#endif

            if(fd == _fdIntrRead)

            {

                assert(_nSelectedReturned >0 && _interruptCount == 0);

                continue;

            }

 

            assert(fd != INVALID_SOCKET);

            if(fd > _lastFd &&(largerFd == INVALID_SOCKET || largerFd > fd))

            {

                largerFd = fd;

            }

 

            if(smallestFd == INVALID_SOCKET ||fd < smallestFd)

            {

                smallestFd = fd;

           }

       }

 

       if(largerFd != INVALID_SOCKET)

       {

            _lastFd = largerFd;

       }

       else

       {

            assert(smallestFd !=INVALID_SOCKET);

            _lastFd = smallestFd;

       }

 

       typename std::map<SOCKET, T*>::const_iterator q =_handlerMap.find(_lastFd);

       if(q == _handlerMap.end())

       {

            Ice::Errorout(_instance->initializationData().logger);

            out << "filedescriptor" << static_cast<int>(_lastFd) << " not registeredwith selector";

            return 0;

       }

       ++_nSelectedReturned;

       return q->second;

#endif

}

7、修改src/IceE/Thread.cpp文件

1)修改包含文件與宏定義

#ifdef VXWORKS

#include<taskLib.h>

extern "C"int sysClkRateGet(void);

#endif

2)修改sleep(…)函數

void

IceUtil::ThreadControl::sleep(constTime& timeout)

{

#ifdef VXWORKS

         struct timeval tv =timeout.gettimeval();

#else

   struct timeval tv = timeout;

#endif

   struct timespec ts;

   ts.tv_sec = tv.tv_sec;

   ts.tv_nsec = tv.tv_usec * 1000L;

   nanosleep(&ts, 0);

}

3)修改Time::now (…)函數

 

Time

IceUtil::Time::now(Clock clock)

{

#if defined(_WIN32_WCE)

   //

   // Note that GetTickCount returns the number of ms since the

   // device was started. Time cannot be used to represent an

   // absolute time on CE since GetLocalTime doesn't have millisecond

   // resolution.

   //

   return Time(static_cast<Int64>(GetTickCount()) * 1000);

#else

   if(clock == Realtime)

   {

# if defined(_WIN32)

       struct _timeb tb;

       _ftime(&tb);

       return Time(static_cast<Int64>(tb.time) * ICE_INT64(1000000) +tb.millitm * 1000);

# else

#ifdef VXWORKS

        struct timespec ts;

        if(clock_gettime(CLOCK_MONOTONIC,&ts) < 0)

        {

            assert(0);

            throwIce::SyscallException(__FILE__, __LINE__, errno);

        }

        return Time(ts.tv_sec *ICE_INT64(1000000) + ts.tv_nsec / ICE_INT64(1000));

#else

       struct timeval tv;

       if(gettimeofday(&tv, 0) < 0)

       {

            assert(0);

            throwIce::SyscallException(__FILE__, __LINE__, errno);

       }

       return Time(tv.tv_sec * ICE_INT64(1000000) + tv.tv_usec);

#endif

# endif

   }

   else

   {

#if defined(_WIN32)

       if(frequency > 0.0)

       {

            Int64 count;

            if(!QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&count)))

            {

                assert(0);

                throwIce::SyscallException(__FILE__, __LINE__, GetLastError());

            }

            returnTime(static_cast<Int64>(count / frequency * 1000000.0));

       }

       else

       {

            struct _timeb tb;

            _ftime(&tb);

            returnTime(static_cast<Int64>(tb.time) * ICE_INT64(1000000) + tb.millitm *1000);

       }

#elif defined(__hpux) ||defined(__APPLE__)

       //

       // Platforms do not support CLOCK_MONOTONIC

       //

       struct timeval tv;

       if(gettimeofday(&tv, 0) < 0)

       {

            assert(0);

            throwIce::SyscallException(__FILE__, __LINE__, errno);

       }

       return Time(tv.tv_sec * ICE_INT64(1000000) + tv.tv_usec);

#else

       struct timespec ts;

       if(clock_gettime(CLOCK_MONOTONIC, &ts) < 0)

       {

            assert(0);

            throwIce::SyscallException(__FILE__, __LINE__, errno);

       }

       return Time(ts.tv_sec * ICE_INT64(1000000) + ts.tv_nsec /ICE_INT64(1000));

#endif

 

   }

#endif

}

4)修改Time:: timeval (…)函數

#ifndef _WIN32

#ifdef VXWORKS

timevalIceUtil::Time::gettimeval() const

{

         timeval tv;

         tv.tv_sec =static_cast<long>(_usec / 1000000);

         tv.tv_usec =static_cast<long>(_usec % 1000000);

         return tv;

}

#else

IceUtil::Time::operator timeval()const

{

   timeval tv;

   tv.tv_sec = static_cast<long>(_usec / 1000000);

   tv.tv_usec = static_cast<long>(_usec % 1000000);

   return tv;

}

#endif

#endif

 

8、創建兩個文件

1)src/IceE/ NormalUtil.h文件

//**********************************************************************

//

//Copyright (c) 2015

//

//2015.02.11

// 平臺軟件部, 上海

// AllRights Reserved

//

//**********************************************************************

#ifndef_NORMALUTIL_H_

#define_NORMALUTIL_H_

 

namespaceIceUtil

{

 

ICE_APIint getFdsetBits(unsigned int nFd);

 

};

 

#endif// _NORMALUTIL_H_

2)src/IceE/ NormalUtil.cpp文件

//**********************************************************************

//

//Copyright (c) 2015

//

//2015.02.11

// 平臺軟件部, 上海

// AllRights Reserved

//

//**********************************************************************

#include<IceE/Config.h>

#include<IceE/NormalUtil.h>

 

staticconst unsigned char bits_table[256] =

{

         0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,

         1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3,4, 4, 5,

         1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3,4, 4, 5,

         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4,5, 5, 6,

         1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4,4, 5,

         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4,5, 5, 6,

         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4,5, 5, 6,

         3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,6, 6, 7,

         1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3,4, 4, 5,

         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4,5, 5, 6,

         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4,5, 5, 6,

         3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,6, 6, 7,

         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4,5, 5, 6,

         3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,6, 6, 7,

         3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,6, 6, 7,

         4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6,7, 7, 8

};

 

int

IceUtil::getFdsetBits(unsignedint nFd)

{

         int nCount = 0;

         nCount = bits_table[nFd & 0xff] + \

                        bits_table[(nFd >> 8) & 0xff];

         return nCount;

}

八、測試範例

這是Ice1.3.0本身自帶的例子,稍微加以修改。兩個工程都是RTP爲基礎,具體如何引用so,以及相關的工程配置,請參考《VxWorks6.6開發共享庫指南要點》文檔。

編譯開關需要增加“-DVXWORKS -D__i386-DICE_API_EXPORTS”

1、創建服務端程序

//**********************************************************************

//

//Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved.

//

// Thiscopy of Ice-E is licensed to you under the terms described in the

//ICEE_LICENSE file included in this distribution.

//

//**********************************************************************

 

#include <IceE/IceE.h>

#include "HelloI.h"

 

using namespace std;

 

int

run(int argc, char*argv[], const Ice::CommunicatorPtr&communicator)

{

    if(argc> 1)

    {

        fprintf(stderr, "%s: too many arguments\n", argv[0]);

        returnEXIT_FAILURE;

    }

 

    Ice::ObjectAdapterPtr adapter =communicator->createObjectAdapter("Hello");

    Demo::HelloPtr object = new HelloI;

    adapter->add(object,communicator->stringToIdentity("hello"));

    adapter->activate();

    communicator->waitForShutdown();

    returnEXIT_SUCCESS;

}

 

int

main(int argc, char*argv[])

{

    int status;

    Ice::CommunicatorPtr communicator;

 

    try

    {

        Ice::InitializationData initData;

        initData.properties =Ice::createProperties();

        initData.properties->load("/d/casco800A/fep/config/config.server");

        communicator = Ice::initialize(argc,argv, initData);

        status = run(argc, argv, communicator);

    }

    catch(const Ice::Exception& ex)

    {

        fprintf(stderr, "%s\n", ex.toString().c_str());

        status = EXIT_FAILURE;

    }

 

    if(communicator)

    {

        try

        {

            communicator->destroy();

        }

        catch(const Ice::Exception& ex)

        {

            fprintf(stderr, "%s\n", ex.toString().c_str());

            status = EXIT_FAILURE;

        }

    }

 

    returnstatus;

}

2、創建客戶端程序

//**********************************************************************

//

//Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved.

//

// Thiscopy of Ice-E is licensed to you under the terms described in the

//ICEE_LICENSE file included in this distribution.

//

//**********************************************************************

 

#include <IceE/IceE.h>

#include "Hello.h"

 

using namespace std;

using namespace Demo;

 

void

menu()

{

    printf("usage:\n");

    printf("t:send greeting as twoway\n");

    printf("o:send greeting as oneway\n");

#ifdef ICEE_HAS_BATCH

    printf("O:send greeting as batch oneway\n");

    printf("f:flush all batch requests\n");

#endif

    printf("T:set a timeout\n");

    printf("P:set a server delay\n");

    printf("s:shutdown server\n");

    printf("x:exit\n");

    printf("?:help\n");

}

 

int

run(int argc, char*argv[], const Ice::CommunicatorPtr&communicator)

{

    if(argc> 1)

    {

        fprintf(stderr, "%s: too many arguments\n", argv[0]);

        returnEXIT_FAILURE;

    }

 

    Ice::PropertiesPtr properties =communicator->getProperties();

    const char* proxyProperty = "Hello.Proxy";

    string proxy = properties->getProperty(proxyProperty);

    if(proxy.empty())

    {

        fprintf(stderr, "%s: property `%s' not set\n", argv[0],proxyProperty);

        returnEXIT_FAILURE;

    }

 

    Ice::ObjectPrx base =communicator->stringToProxy(proxy);

    HelloPrx twoway = HelloPrx::checkedCast(base->ice_twoway()->ice_timeout(-1));

    if(!twoway)

    {

        fprintf(stderr, "%s: invalid proxy\n", argv[0]);

        returnEXIT_FAILURE;

    }

    HelloPrx oneway = twoway->ice_oneway();

#ifdef ICEE_HAS_BATCH

    HelloPrx batchOneway = twoway->ice_batchOneway();

#endif

 

    int timeout= -1;

    int delay =0;

 

    menu();

 

    char c =EOF;

    do

    {

        try

        {

            printf("==>"); fflush(stdout);

            do

            {

                c = getchar();

            }

            while(c!= EOF && c =='\n');

            if(c== 't')

            {

                twoway->sayHello(delay);

            }

            elseif(c =='o')

            {

                oneway->sayHello(delay);

            }

#ifdef ICEE_HAS_BATCH

            elseif(c =='O')

            {

               batchOneway->sayHello(delay);

            }

            elseif(c =='f')

            {

               batchOneway->ice_flushBatchRequests();

            }

#endif

            elseif(c =='T')

            {

                if(timeout== -1)

                {

                    timeout = 2000;

                }

                else

                {

                    timeout = -1;

                }

               

                twoway = twoway->ice_timeout(timeout);

                oneway =oneway->ice_timeout(timeout);

#ifdef ICEE_HAS_BATCH

                batchOneway =batchOneway->ice_timeout(timeout);

#endif               

                if(timeout== -1)

                {

                    printf("timeoutis now switched off\n");

                }

                else

                {

                    printf("timeout is now set to 2000ms\n");

                }

            }

            elseif(c =='P')

            {

                if(delay== 0)

                {

                    delay = 2500;

                }

                else

                {

                    delay = 0;

                }

               

                if(delay== 0)

                {

                    printf("serverdelay is now deactivated\n");

                }

                else

                {

                    printf("server delay is now set to 2500ms\n");

                }

            }

            elseif(c =='s')

            {

               twoway->shutdown();

            }

            elseif(c =='x')

            {

                //Nothing to do

            }

            elseif(c =='?')

            {

                menu();

            }

            else

            {

                printf("unknowncommand `%c'\n", c);

                menu();

            }

        }

        catch(const Ice::Exception& ex)

        {

            fprintf(stderr, "%s\n", ex.toString().c_str());fflush(stderr);

        }

    }

    while(c !=EOF && c != 'x');

 

    returnEXIT_SUCCESS;

}

 

int

main(int argc, char*argv[])

{

    int status;

    Ice::CommunicatorPtr communicator;

 

    try

    {

        Ice::InitializationData initData;

        initData.properties =Ice::createProperties();

        initData.properties->load("/d/casco800A/fep/config/config.client");

        communicator = Ice::initialize(argc,argv, initData);

        status = run(argc, argv, communicator);

    }

    catch(const Ice::Exception& ex)

    {

        fprintf(stderr, "%s\n", ex.toString().c_str());

        status = EXIT_FAILURE;

    }

 

    if(communicator)

    {

        try

        {

            communicator->destroy();

        }

        catch(const Ice::Exception& ex)

        {

            fprintf(stderr, "%s\n", ex.toString().c_str());

            status = EXIT_FAILURE;

        }

    }

 

    returnstatus;

}

3、運行測試

3.1、執行客戶與服務程序


圖8.1 並行運行的程序以不同顏色標識

3.2、查看端口使用狀況

1)啓動服務端時的狀態

-> netstat "-ap tcp"

INET sockets

Prot  Fd   Recv-Q Send-Q Local Address                 Foreign Address               State

TCP   46   0     0      localhost.49176               localhost.49175               ESTABLISHED

TCP   47   0     0      localhost.49175               localhost.49176               ESTABLISHED

TCP   49   0     0      localhost.49178               localhost.49177               ESTABLISHED

TCP   50   0     0      localhost.49177               localhost.49178               ESTABLISHED

TCP   51   0     0      localhost.10000               0.0.0.0.*                     LISTEN    

TCP   53   0     0      localhost.49180               localhost.49179               ESTABLISHED

TCP   54   0     0      localhost.49179               localhost.49180               ESTABLISHED

 

INET6 sockets

Prot  Fd   Recv-Q Send-Q Local Address                 Foreign Address               State

 

 

value = 0 = 0x0

->

2)啓動客戶端時的狀態

-> netstat "-ap tcp"

INET sockets

Prot  Fd   Recv-Q Send-Q Local Address                 Foreign Address               State

TCP   46   0     0      localhost.49176               localhost.49175               ESTABLISHED

TCP   47   0     0      localhost.49175               localhost.49176               ESTABLISHED

TCP   49   0     0      localhost.49178               localhost.49177               ESTABLISHED

TCP   50   0     0      localhost.49177               localhost.49178               ESTABLISHED

TCP   51   0     0      localhost.10000               0.0.0.0.*                     LISTEN    

TCP   53   0     0      localhost.49180               localhost.49179               ESTABLISHED

TCP   54   0     0      localhost.49179               localhost.49180               ESTABLISHED

TCP   56   0     0      localhost.49182               localhost.49181               ESTABLISHED

TCP   57   0     0      localhost.49181               localhost.49182               ESTABLISHED

TCP   59   0     0      localhost.49184               localhost.49183               ESTABLISHED

TCP   60   0     0      localhost.49183               localhost.49184               ESTABLISHED

TCP   61   0     0      localhost.49185               localhost.10000               ESTABLISHED

TCP   62   0     0      localhost.10000               localhost.49185               ESTABLISHED

 

INET6 sockets

Prot  Fd   Recv-Q Send-Q Local Address                 Foreign Address               State

 

 

value = 0 = 0x0

->

3.3、控制檯輸出結果

1)testclient.vxe控制檯

usage:

t: send greeting as twoway

o: send greeting as oneway

O: send greeting as batch oneway

f: flush all batch requests

T: set a timeout

P: set a server delay

s: shutdown server

x: exit

?: help

==> t

輸入命令t,回車

2)testIce130控制檯

      Hello World!

 

現在你看到上面的輸出結果,這是否令人激動呢?!

九、總結

         本文詳細描述了基於POSIX移植可能出現的問題,修改的代碼並不是很大,我相信按照上述的步驟,移植iceE1.3.0到VxWorks操作系統下並不是難事了,你可以省下zeroC公司商業方面的技術支持費用了。

         你可能發現本文並沒使用ice的makefile自動編譯,爲了簡便移植工作,防止在vxWorks開發環境中安裝第三方的庫過於複雜。因此,我們只要從Windows下拷貝已經生成的源碼,在此基礎上再進行修改移植即可。

         我們已經成功地移植了 IceE1.3.0,如何在VxWorks操作系統中正確部署,那就看你的架構了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章