免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 852 | 回复: 0
打印 上一主题 下一主题

Linux IPC备忘 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-11-03 18:43 |只看该作者 |倒序浏览
        大概在很久之前就一直关注的ipc问题因为一直没有怎么使用也不是很明了,实在是为了自己的懒惰而汗颜了。经典的ipc里面除了自己曾经用到过的pthread_mutex之外,对其他的几种都不了解。自己学习的话也说了不少,可是都没有什么效果,看书似乎都看不动。
        最近整理了一下几种ipc方式的使用,一些小问题,在此存档:
一.posix的msgqueue的支持问题。
        要说明的是从一开始就觉得所谓的posix的兼容是很好的一个东西,而linux对posix的兼容性很好也是一直以来发展linuxer的一个重要的游说砝码。但是在开始测试posix message queue的时候遭到了当头一棒。程序编译通过,连接出错!然后google到nptl的知识,声称posix msgqueue的支持在mm分支中发展。晕先。不甘心的同时在新下载的2.6.18里面发现了如下说明:
2.6.18的内核里面关于posix message-queue的选项说明:
    CONFIG_POSIX_MQUEUE:                                                      
                                                                           
   POSIX variant of message queues is a part of IPC. In POSIX message      
   queues every message has a priority which decides about succession      
   of receiving it by a process. If you want to compile and run            
   programs written e.g. for Solaris with use of its POSIX message         
   queues (functions mq_*) say Y here. To use this feature you will        
   also need mqueue library, available from                                
                           
                                                                           
   POSIX message queues are visible as a filesystem called 'mqueue'        
   and can be mounted somewhere if you want to do filesystem               
   operations on message queues.                                          
                                                                           
   If unsure, say Y.                                                      
                                                                           
   Symbol: POSIX_MQUEUE [=y]                                               
   Prompt: POSIX Message Queues                                            
     Defined at init/Kconfig:118                                          
     Depends on: NET && EXPERIMENTAL
    同时在2.6.16里面这个还是没有的,真是庆幸啊,要是早点开始关注这个岂不是要郁闷很久或者麻烦很久。遵照上面内核编译系统给出的信息,上网站一看原来已经转到了:http://www.geocities.com/wronski12/posix_ipc/index.html.下载了:libmqueue-4.41.tar.gz。经典的三步之后再编译。bingle!
    程序清单:posixqueue.c
#include
#include
#include
#include
#include
#include
#include
#include
#define MSGQUEUE_NAME "/tllmsgqueue"
#define MAXMSGNAMELENGTH 32
#define MSGQUEUE_LENGTH 128
#define MSG_LENGTH 64
struct parameters
{
    char msgQueueName[MAXMSGNAMELENGTH];
    struct mq_attr msgattr;
    unsigned int timeInterval;
};
void msgSendThread(void  * data)
{
    //pthread_detach(pthread_self());
    struct parameters * para=(struct parameters *)data;
    mq_unlink(para->msgQueueName);
    mqd_t mqid;
    char  buffer[MSG_LENGTH]={0};
    unsigned int counter=0;
    mode_t mode;
    mode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
    mqid=mq_open(para->msgQueueName,para->msgattr.mq_flags,mode,&(para->msgattr));
    if(mqid == -1)
    {
        switch(errno)
        {
            case EACCES:
                printf("EACCES------------\n");
                break;
            case EEXIST:
                printf("EEXIST------------\n");
                break;
            case EINTR:
                printf("EINTR------------\n");
                break;
            case EINVAL:
                printf("EINVAL------------\n");
                break;
            case ENAMETOOLONG:
                printf("ENAMETOOLONG------------\n");
            case ENOENT:
                printf("ENOENT------------\n");
                break;
            case ENOMEM:
                printf("ENOMEM------------\n");
                break;
            case ENOSPC:
                printf("ENOSPC------------\n");
                break;
            case EFAULT:
                printf("EFAULT------------\n");
                break;
            case EMFILE:
                printf("EMFILE------------\n");
                break;
            case ENFILE:
                printf("ENFILE------------\n");
                break;
            default:
                break;
        }
        printf("SendThread:open msqueue failed!\n");
        return;
    }
    for(;countermsgQueueName,para->msgattr.mq_flags,mode,&(para->msgattr));
    if(mqid == -1)
    {
        switch(errno)
        {
            case EACCES:
                printf("EACCES------------\n");
                break;
            case EEXIST:
                printf("EEXIST------------\n");
                break;
            case EINTR:
                printf("EINTR------------\n");
                break;
            case EINVAL:
                printf("EINVAL------------\n");
                break;
            case ENAMETOOLONG:
                printf("ENAMETOOLONG------------\n");
            case ENOENT:
                printf("ENOENT------------\n");
                break;
            case ENOMEM:
                printf("ENOMEM------------\n");
                break;
            case ENOSPC:
                printf("ENOSPC------------\n");
                break;
            case EFAULT:
                printf("EFAULT------------\n");
                break;
            case EMFILE:
                printf("EMFILE------------\n");
                break;
            case ENFILE:
                printf("ENFILE------------\n");
                break;
            default:
                break;
        }   
        printf("ReceiveThread:open msqueue failed!\n");
        return;
    }
    unsigned int nreads=0;
    for(;;)
    {
        mq_getattr(mqid,&privateAttr);
        while(privateAttr.mq_curmsgs>0)
        {
cread:
            nreads=mq_receive(mqid,buffer,MSG_LENGTH,NULL);
            if(strncmp(buffer,"quit",4) ==0 )
            {
                goto rend;
            }
            printf("\t\tread %d bytes,message is:%s.\n",nreads,buffer);
            mq_getattr(mqid,&privateAttr);
        }
        goto cread;
    }
rend:
    mq_unlink(para->msgQueueName);
    mq_close(mqid);
    printf("now receive thread quit.\n");
    return;
}
int main(void)
{
    struct parameters myPara;
    memset((void *)&myPara,0,sizeof(struct parameters));
    strncat(myPara.msgQueueName,MSGQUEUE_NAME,MAXMSGNAMELENGTH);
    //myPara.msgattr.mq_flags=O_RDWR|O_CREAT|O_NONBLOCK;
    myPara.msgattr.mq_flags=O_RDWR|O_CREAT;
    myPara.msgattr.mq_maxmsg=MSGQUEUE_LENGTH;
    myPara.msgattr.mq_msgsize=MSG_LENGTH;
    myPara.msgattr.mq_curmsgs=0;
    myPara.timeInterval=1;
    pthread_t pids;
    pthread_t pidr;
    pthread_create(&pids,NULL,(void *)msgSendThread,&myPara);
    pthread_create(&pidr,NULL,(void *)msgReceiveThread,&myPara);
    pthread_join(pids,NULL);
    pthread_join(pidr,NULL);
    printf("now main thread quit.\n");
    return 0;
}
二.mmap的问题:
        因为前面的posix的消息队列的问题慢慢就觉得posix毕竟还是不如sysV在unix系列的操作系统上来得通用,然后先把sysV的ipc方式都试用了一遍再试用posix方式的时候,犯了思维惯性的错误。因为sysV的share memory方式是“自动扩展”的(或者是达到一种“自动扩展”的效果),所以在试用posix方式shm的时候没有注意mmap是不具备“自动扩展”功能的,所以就一直卡在“总线错误”这个运行错误上。其实说起来这个错误提示也是有点怪,google了很久也没有明确的说明。好在最后还是搞定了。
程序清单:posixshm.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "myerr.h"
#define SEM_WRITER "/tmptestllsemw"
#define SEM_READER "/tmptestllsemr"
#define SHM_NAME "/tmptestllshm"
#define SHMSIZE 64
struct ThreadPara
{
    sem_t * reader;
    sem_t * writer;
    int shmid;
    int shmsize;
};
void writerThread(void  * data)
{
    unsigned int counter=0;
    struct ThreadPara * myPa=(struct ThreadPara *)data;
    char * buffer;
    buffer=mmap(NULL,myPa->shmsize,PROT_READ|PROT_WRITE,MAP_SHARED,myPa->shmid,0);
    printf("writer:get buffer address is:%x.\n",(unsigned int)buffer);
   
    for(counter=0;counterwriter);
        sprintf((char *)buffer,"this is the posix shm #%d message",counter);
        sem_post(myPa->reader);
        sleep(1);
    }
   
    sem_wait(myPa->writer);
    memset(buffer,0,myPa->shmsize);
    sprintf(buffer,"quitnow");
    sem_post(myPa->reader);
    munmap(buffer,myPa->shmsize);
    printf("now send thread quit.\n");
    return;
}
void readerThread(void  * data)
{
    struct ThreadPara * myPa=(struct ThreadPara *)data;
    void * buffer;
    buffer=mmap(NULL,myPa->shmsize,PROT_READ|PROT_READ,MAP_SHARED,myPa->shmid,0);
    printf("reader:get buffer address is:%x.\n",(unsigned int )buffer);
    for(;;)
    {
        sem_wait(myPa->reader);
        if(strncmp((char *)buffer,"quitnow",7) == 0)
        {
            break;
        }
        printf("\tYes,i got buffer:%s.\tthis is shm realization.\n",(char *)buffer);
        sem_post(myPa->writer);
    }
    munmap(buffer,myPa->shmsize);
    printf("now receive thread quit.\n");
    return;
}
int main(void)
{
    struct ThreadPara myPara;
    int oFlag;
    mode_t oMode;
   
    memset(&myPara,0,sizeof(struct ThreadPara));
   
    oFlag=O_CREAT;
    oMode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
    sem_unlink(SEM_READER);
    sem_unlink(SEM_WRITER);
    myPara.reader=sem_open(SEM_READER,oFlag,oMode,0);
    if(myPara.reader
三.如果是简单的信号量的使用的话还是posix的信号量用起来简单一些,和mutex有点象吧。
最后:其他没什么问题。一些说明就是虽然这里说的ipc的问题,但是到底是将多个工作流程实现为多进程,还是将多个工作流程实现为多线程。还是具体问题具体分析吧,比如考虑到实时性,考虑的进程轮换的开销等等,不过大致的想来似乎是一样,按照“内核线程”的模型,多线程似乎还节省了进程切换的开销呢。呵呵。先这么臆断吧,也不知道是不是正确的,有机会测试一下。
而这里图个方便,就全部都是采用开线程测试的。也是做个备忘的意思,几个程序的清单如下:
sysvqueue.c
#include
#include
#include
#include
#include
#include
#include
#include
#define MSGQUEUE_NAME "/tmp/tllmsgqueue"
#define MSGQUEUE_ID 0
#define MAXMSGNAMELENGTH 32
#define MSGQUEUE_LENGTH 128
#define MSG_LENGTH 64
struct parameters
{
    key_t mqid;
    struct msqid_ds qds;
    int oflag;
};
void msgSendThread(void  * data)
{
    //pthread_detach(pthread_self());
    struct parameters * para=(struct parameters *)data;
    int mqid;
    char  buffer[MSG_LENGTH]={0};
    unsigned int counter=0;
    mqid=msgget(para->mqid,para->oflag);
    if(mqid == -1)
    {
        return;
    }
    for(;countermqid,para->oflag);
    if(mqid == -1)
    {
        return;
    }
    unsigned int nreads=0;
    for(;;)
    {
        msgctl(mqid,IPC_STAT,&(para->qds));
        while(para->qds.msg_qnum>0)
        {
doread:
            nreads=msgrcv(mqid,buffer,MSG_LENGTH,0,0);
            if(errno == EIDRM)
            {
                goto abquit;
            }
            if(strncmp(buffer,"quit",4)==0)
            {
                goto endreceive;
            }
            printf("read %hd bytes,message is:%s.\n",nreads,buffer);
            msgctl(mqid,IPC_STAT,&(para->qds));
        }
        goto doread;
    }
endreceive:
    msgctl(mqid,IPC_RMID,NULL);
abquit:
    printf("receive thread quit now .\n");
    return;
}
int main(void)
{
    struct parameters myPara;
    memset((void *)&myPara,0,sizeof(struct parameters));
#ifdef PRIVATEIPC
    myPara.mqid=IPC_PRIVATE;
#else
    myPara.mqid=ftok(MSGQUEUE_NAME,MSGQUEUE_ID);
#endif
    myPara.oflag=IPC_CREAT;
   
    pthread_t pids;
    pthread_t pidr;
    pthread_create(&pids,NULL,(void *)msgSendThread,&myPara);
    pthread_create(&pidr,NULL,(void *)msgReceiveThread,&myPara);
    pthread_join(pidr,NULL);
    //printf("\tnow is here!\n");
    pthread_join(pids,NULL);
    printf("main thread quit now.\n");
    return 0;
}
sysvsem.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SEM_NAME "/tmp/testllsem"
#define SEM_ID 0
#define BUFFERSIZE 64
#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
/* union semun is defined by including  */
#else
/* according to X/OPEN we have to define it ourselves */
union semun {
     int val;                  /* value for SETVAL */
     struct semid_ds *buf;     /* buffer for IPC_STAT, IPC_SET */
     unsigned short *array;    /* array for GETALL, SETALL */
                   /* Linux specific part: */
     struct seminfo *__buf;    /* buffer for IPC_INFO */
};
#endif
struct ThreadPara
{
    key_t kid;
    int semid;
    unsigned int readerIndex;
    unsigned int writerIndex;
    char buffer[BUFFERSIZE];
};
void writerThread(void  * data)
{
    unsigned int counter=0;
    struct ThreadPara * myPa=(struct ThreadPara *)data;
    struct sembuf semops;
    semops.sem_flg=SEM_UNDO;
    for(;counterwriterIndex;
        semops.sem_op=-1;
        //semops.sem_flg=SEM_UNDO;
        semop(myPa->semid,&semops,1);
        sprintf(myPa->buffer,"this is the #%d message",counter);
        semops.sem_num=myPa->readerIndex;
        semops.sem_op=1;
        //semops.sem_flg=0;
        semop(myPa->semid,&semops,1);
        //sleep(1);
    }
   
    semops.sem_num=myPa->writerIndex;
    semops.sem_op=-1;
    //semops.sem_flg=0;
    semop(myPa->semid,&semops,1);
    memset(myPa->buffer,0,BUFFERSIZE);
    sprintf(myPa->buffer,"quitnow");
    semops.sem_num=myPa->readerIndex;
    semops.sem_op=1;
    //semops.sem_flg=0;
    semop(myPa->semid,&semops,1);
    printf("now send thread quit.\n");
    return;
}
void readerThread(void  * data)
{
    struct ThreadPara * myPa=(struct ThreadPara *)data;
    struct sembuf semops;
    semops.sem_flg=SEM_UNDO;
    for(;;)
    {
        semops.sem_num=myPa->readerIndex;
        semops.sem_op=-1;
        //semops.sem_flg=0;
        semop(myPa->semid,&semops,1);
        if(strncmp(myPa->buffer,"quitnow",7) == 0)
        {
            break;
        }
        printf("\tYes,i got buffer:%s.\n",myPa->buffer);
        semops.sem_num=myPa->writerIndex;
        semops.sem_op=1;
        //semops.sem_flg=0;
        semop(myPa->semid,&semops,1);
    }
    printf("now receive thread quit.\n");
    return;
}
int main(void)
{
    struct ThreadPara myPara;
    int oFlag;
    //mode_t oMode;
    union semun arg;
    memset(&myPara,0,sizeof(struct ThreadPara));
   
    oFlag=IPC_CREAT|IPC_EXCL;
    //oMode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
#ifdef PRIVATEIPC
    myPara.kid=IPC_PRIVATE;
#else
    myPara.kid=ftok(SEM_NAME,SEM_ID);
#endif
    myPara.semid=semget(myPara.kid,2,oFlag);
    myPara.readerIndex=0;
    myPara.writerIndex=1;
    arg.val=0;
    semctl(myPara.semid,myPara.readerIndex,SETVAL,arg);
    arg.val=1;
    semctl(myPara.semid,myPara.writerIndex,SETVAL,arg);
    if(myPara.semid
sysvshm.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SEM_NAME "/tmp/testllsem"
#define SEM_ID 0
#define SHM_NAME "/tmp/testllshm"
#define SHM_ID 0
#define SHMSIZE 64
#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
/* union semun is defined by including  */
#else
/* according to X/OPEN we have to define it ourselves */
union semun {
     int val;                  /* value for SETVAL */
     struct semid_ds *buf;     /* buffer for IPC_STAT, IPC_SET */
     unsigned short *array;    /* array for GETALL, SETALL */
                   /* Linux specific part: */
     struct seminfo *__buf;    /* buffer for IPC_INFO */
};
#endif
struct ThreadPara
{
    key_t ksemid;
    key_t kshmid;
    int semid;
    int shmid;
    unsigned int readerIndex;
    unsigned int writerIndex;
    int shmsize;
};
void writerThread(void  * data)
{
    unsigned int counter=0;
    struct ThreadPara * myPa=(struct ThreadPara *)data;
    void * buffer;
    struct sembuf semops;
    semops.sem_flg=SEM_UNDO;
    buffer=shmat(myPa->shmid,NULL,0);
    for(;counterwriterIndex;
        semops.sem_op=-1;
        //semops.sem_flg=SEM_UNDO;
        semop(myPa->semid,&semops,1);
        sprintf(buffer,"this is the #%d message",counter);
        semops.sem_num=myPa->readerIndex;
        semops.sem_op=1;
        //semops.sem_flg=0;
        semop(myPa->semid,&semops,1);
        //sleep(1);
    }
   
    semops.sem_num=myPa->writerIndex;
    semops.sem_op=-1;
    //semops.sem_flg=0;
    semop(myPa->semid,&semops,1);
    memset(buffer,0,myPa->shmsize);
    sprintf(buffer,"quitnow");
    semops.sem_num=myPa->readerIndex;
    semops.sem_op=1;
    //semops.sem_flg=0;
    semop(myPa->semid,&semops,1);
    shmdt(buffer);
    printf("now send thread quit.\n");
    return;
}
void readerThread(void  * data)
{
    struct ThreadPara * myPa=(struct ThreadPara *)data;
    void * buffer;
    struct sembuf semops;
    semops.sem_flg=SEM_UNDO;
    buffer=shmat(myPa->shmid,NULL,SHM_RDONLY);
    for(;;)
    {
        semops.sem_num=myPa->readerIndex;
        semops.sem_op=-1;
        //semops.sem_flg=0;
        semop(myPa->semid,&semops,1);
        if(strncmp(buffer,"quitnow",7) == 0)
        {
            break;
        }
        printf("\tYes,i got buffer:%s.\tthis is shm realization.\n",(char *)buffer);
        semops.sem_num=myPa->writerIndex;
        semops.sem_op=1;
        //semops.sem_flg=0;
        semop(myPa->semid,&semops,1);
    }
    shmdt(buffer);
    printf("now receive thread quit.\n");
    return;
}
int main(void)
{
    struct ThreadPara myPara;
    int oFlag;
    //mode_t oMode;
    union semun arg;
    memset(&myPara,0,sizeof(struct ThreadPara));
   
    oFlag=IPC_CREAT|IPC_EXCL;
    //oMode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
#ifdef PRIVATEIPC
    myPara.ksemid=IPC_PRIVATE;
    myPara.kshmid=IPC_PRIVATE;
#else
    myPara.ksemid=ftok(SEM_NAME,SEM_ID);
    myPara.kshmid=ftok(SHM_NAME,SHM_ID);
#endif
    myPara.shmsize=SHMSIZE;
    myPara.semid=semget(myPara.ksemid,2,oFlag);
    if(myPara.semid
posixsem.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SEM_WRITER "/testllposixsemw"
#define SEM_READER "/testllposixsemr"
#define BUFFERSIZE 64
struct ThreadPara
{
    sem_t * reader;
    sem_t * writer;
    char buffer[BUFFERSIZE];
};
void writerThread(void  * data)
{
    unsigned int counter=0;
    struct ThreadPara * myPa=(struct ThreadPara *)data;
    for(;counterwriter);
        sprintf(myPa->buffer,"writer:this is the POSIX_SEM #%d message",counter);
        sem_post(myPa->reader);
        //sleep(1);
    }
   
    sem_wait(myPa->writer);
    memset(myPa->buffer,0,BUFFERSIZE);
    sprintf(myPa->buffer,"quitnow");
    sem_post(myPa->reader);
    printf("now send thread quit.\n");
    return;
}
void readerThread(void  * data)
{
    struct ThreadPara * myPa=(struct ThreadPara *)data;
    for(;;)
    {
        sem_wait(myPa->reader);
        if(strncmp(myPa->buffer,"quitnow",7) == 0)
        {
            break;
        }
        printf("\treader:Yes,i got buffer:%s.\n",myPa->buffer);
        sem_post(myPa->writer);
        //sleep(3);
    }
    printf("now receive thread quit.\n");
    return;
}
int main(void)
{
    struct ThreadPara myPara;
    int oFlag;
    mode_t oMode;
    memset(&myPara,0,sizeof(struct ThreadPara));
   
    //oFlag=O_CREAT|O_EXCL;
    oFlag=O_CREAT;
    oMode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
    myPara.reader=sem_open(SEM_READER,oFlag,oMode,0);
    if(myPara.reader
外加一个简陋的Makefile。
CFLAGS=-O9 -Wall -g -D__POSIX_SOURCE
CINCLUDES=
CLIBS=-lpthread -lrt
POSIXQUEUELIB=-lmqueue
CC=gcc
all:tm one two tcrc pq vq psem vsem vshm pshm
pshm:posixshm.c
    $(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o pshm posixshm.c
   
vshm:sysvshm.c
    $(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o vshm sysvshm.c
   
psem:posixsem.c
    $(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o psem posixsem.c
   
vsem:sysvsem.c
    $(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o vsem sysvsem.c
vq:sysvqueue.c
    $(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o vq sysvqueue.c
pq:posixqueue.c
    $(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) $(POSIXQUEUELIB) -o pq posixqueue.c
tcrc:testcrc.c
    $(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o tcrc testcrc.c
tm:testmain.c
    $(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o tm testmain.c
one:one.c
    $(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o one one.c
two:two.c
    $(CC) $(CFLAGS) $(CINCLUDES) $(CLIBS) -o two two.c
clean:
    rm -f vshm
    rm -f pshm
    rm -f vsem
    rm -f psem
    rm -f pq
    rm -f vq
    rm -f tcrc
    rm -f one
    rm -f two
    rm -f tm
    rm -f a.out
留此备忘。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/17564/showart_194971.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP