一、前言

ICE1.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线程相关的函数

VxWorks Test Posix

图3.1 创建RTP工程

build spec

图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  0) 
    { 
        stopTask(nId1); 
    } 
 
    if (nId2 > 0) 
    { 
        stopTask(nId2); 
    } 
 
    rc =pthread_mutex_destroy(&__mutex); 
 
    if (rc != 0) 
    { 
        return -1; 
    } 
 
    return 0; 
} 
2、运行测试代码

ICE debug

图3.3 选择vxsim0仿真

ICE Run

图3.4 运行之后的结果

当程序代码执行pthread_create时,返回结果始终为“-1”,这里你必须对VxWorks的POSIX过程要熟悉了。经过查询有关错误代码资料 (#define ENOSYS 71 /*Function not implemented */), 我们发现VxWorks提供的仿真器功能很基础,但有很多组件未包含进来,于是我们需要定制自己的镜像文件,详细过程参考图5.8-5.9。

ICE task

图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镜像文件

ICE Project

图4.1 创建VxWorks镜像文件

ICE New Project

图4.2 工程名称为vxworks_i386

ICE SIMPC DIAB

图4.3 选择BSP和编译器

ICE Option

图4.4 该选择默认

ICE Profile

图4.5 选择PROFILE_DEVELOPMENT

ICE Indexer

图4.6 完成向导

ICE File Tree

图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");
    }       

五、创建新连接

ice remote system

图5.1 新建一个仿真连接

ice connection

图5.2 选择上述生成的镜像文件

ice mem

图5.3 定制内存大小,此项默认即可

ice belownormal

图5.4 优先级为belowNormal

ice wdbpipe

图5.5 设置目标服务选择

ice map

图5.6 设置路径对象映射关系

ice vsim2

图5.7 完成向导

ice posix schedule

图5.8 剪裁包含POSIX线程调度组件

ice component

图5.9有效的POSIX线程组件

ice vxsim2 launch

图5.10 启动连接vxsim2

六、创建libice130动态连接库

如何创建动态连接库及使用调用,参考之前《VxWorks6.6开发共享库指南要点》文档,然后工程注意事项如下:

编译开关需要增加“-DVXWORKS -D__i386 -DICE_API_EXPORTS-Xrtti”

ice code generation

图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 
typedef int ssize_t;
#else
#  include "unistd.h"
#  include "fcntl.h"
#  include "sys/socket.h"
<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 "signal.h"
# include  
#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 
#   include 
#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(&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(&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 
#endif

#ifdef VXWORKS
#   include 
#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(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(_events[i].data.ptr); 
#else 
            T* handler =reinterpret_cast(_events[i].udata); 
#endif 
            if(!handler) // _fdIntrRead 
            { 
                assert(_nSelectedReturned >0 && _interruptCount == 0); 
                continue; 
            } 
            if(handler->_fd > _lastFd&& (larger == 0 || handler->_fd _fd)) 
            { 
                larger = handler; 
            } 
            if(smallest == 0 || handler->_fd_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 initializationData().logger); 
            out << "select() inselector returned " << _nSelected << " but no filedescriptoris ready"; 
            return 0; 
        } 
        int nfdSetCount = 0;  
        const fd_set* fdSet; 
        if (_nSelectedReturned 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 fd_count; ++i) 
        { 
            SOCKET fd = fdSet->fd_array[i]; 
#endif 
#else 
        for(std::vector::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 ::const_iterator q =_handlerMap.find(_lastFd); 
        if(q == _handlerMap.end()) 
        { 
            Ice::Errorout(_instance->initializationData().logger); 
            out << "filedescriptor" <(_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(GetTickCount()) * 1000); 
#else 
    if(clock == Realtime) 
    { 
# if defined(_WIN32) 
        struct _timeb tb; 
        _ftime(&tb); 
        return Time(static_cast(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(&count))) 
            { 
                assert(0); 
                throwIce::SyscallException(__FILE__, __LINE__, GetLastError()); 
            } 
            returnTime(static_cast(count / frequency * 1000000.0)); 
        } 
        else 
        { 
            struct _timeb tb; 
            _ftime(&tb); 
            returnTime(static_cast(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(_usec / 1000000);
         tv.tv_usec =static_cast(_usec % 1000000);
         return tv;
}
#else
IceUtil::Time::operator timeval()const
{
   timeval tv;
   tv.tv_sec = static_cast(_usec / 1000000);
   tv.tv_usec = static_cast(_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; 
        } 
    } 
    return(status); 
} 

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);
		return(EXIT_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]);
	return(EXIT_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');

	return(EXIT_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;
		}
	}
	return(status);
}

3、运行测试

3.1、执行客户与服务程序

ice debug function

图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操作系统中正确部署,那就看你的架构了。