2013-08-11 5 views
0

Я пишу автопоток мультиплексора в java, который должен читать пустое количество FileDescriptors. Чтобы прочитать дескрипторы файлов (или сокет и т. Д., У которых есть FileDescriptor), мне нужна точная душа, если у меня есть некоторые дескрипторы, и нет никакого события, не повторяйте все. А вот метод som в linux: select, poll. Я пытался использовать эти методы, но безуспешно. нативные коды:выбор и опрос не работают правильно

JNIEXPORT jint JNICALL Java_hu_ddsi_java_Native_JUnix_select(JNIEnv * env,jobject obj,jobjectArray fds,long timeout_s,long timeout_us) 
{ 

    int len = env->GetArrayLength(fds); 
    jclass cls = env->FindClass("java/io/FileDescriptor"); 
    jfieldID fid = env->GetFieldID(cls, "fd", "I"); 
    fd_set watch; 
    int buf = 0; 
    int max = 0; 

    for(int i=0;i < len;i++) 
    { 
     FD_SET(buf=(int) env->GetIntField(env->GetObjectArrayElement(fds, i),fid),&watch); 
     if(buf>max) 
      max = buf; 
    } 

    struct timeval *timeout = (timeval*) malloc(sizeof(struct timeval)); 
    timeout->tv_sec = timeout_s; 
    timeout->tv_usec = timeout_us; 

    return select(max+1, &watch, NULL,NULL,timeout); 
} 

JNIEXPORT jint JNICALL Java_hu_ddsi_java_Native_JUnix_poll(JNIEnv * env,jobject obj,jlongArray pollfds,int timeout_ms) 
{ 
    unsigned int nfds = env->GetArrayLength(pollfds); 

    void* pointerfor = malloc(nfds*(sizeof(void*))); 

    for(int i=0;i < nfds;i++) 
     env->GetLongArrayRegion(pollfds,i,1,(jlong*) pointerfor+(sizeof(void*)*i)); 

    return poll(((struct pollfd*)pointerfor), nfds,timeout_ms); 
} 

JNIEXPORT jlong JNICALL Java_hu_ddsi_java_Native_JUnix_pollfd(JNIEnv * env,jobject obj,jobject fd,jshort events,jshort revents) 
{ 
    jclass cls = env->FindClass("java/io/FileDescriptor"); 
    jfieldID fid = env->GetFieldID(cls, "fd", "I"); 

    struct pollfd *pfd = (pollfd*) malloc(sizeof(pollfd)); 
     pfd->fd = env->GetIntField(fd,fid); 
     pfd->events = events; 
     pfd->revents = 0x0; 

    return (jlong) pfd; 
} 

JNIEXPORT jint JNICALL Java_hu_ddsi_java_Native_JUnix_pollfdfd(JNIEnv * env,jobject obj,jlong pfd_struct) 
{ 
    return ((struct pollfd*)pfd_struct)->fd; 
} 

JNIEXPORT jshort JNICALL Java_hu_ddsi_java_Native_JUnix_pollfdevents(JNIEnv * env,jobject obj,jlong pfd_struct) 
{ 
    return ((struct pollfd*)pfd_struct)->events; 
} 

JNIEXPORT jshort JNICALL Java_hu_ddsi_java_Native_JUnix_pollfdrevents(JNIEnv * env,jobject obj,jlong pfd_struct) 
{ 
    return ((struct pollfd*)pfd_struct)->revents; 
} 

И тест-код в Java:

public static void main(String args[]) throws Throwable 

     final FileInputStream is = new FileInputStream("/var/log/apache2/access.log"); 
     long st = JUnix.pollfd(is.getFD(),(short)(JUnix.POLLIN|JUnix.POLLPRI)); 
     int len = 0; 
     while(true) 
     { 

      System.out.println("ava:"+(len = is.available())); 

      for(int i=0;i < len;i++) 
       System.out.print((char) is.read()); 

//   JUnix.select(new FileDescriptor[]{is.getFD()},5,0); 

      System.out.println("pollretval: "+JUnix.poll(new long[]{st},-1)); 
      System.out.println("revent: "+JUnix.pollfdrevents(st)); 
      System.out.println("pollfd: "+JUnix.pollfdfd(st)); 
     } 
    } 

И когда я просматриваю, я должен увидеть новые строки в терминале, но он будет заблокирован навсегда ... если я изменю таймаут, я поставлю теперь строки в моем терминале.

Иногда код сходить с ума и печать infintly:

ava:0 
pollretval: 1 
revent: 0 
pollfd: 10 

этот результат интересен, FileDescriptor таким же, произрастающий опрос вернулся с модифицированными Fd номерами, но в pollfd stuct Ревента поле ... он должен быть изменен, если произошло событие. Я тестировал, указатели находятся в хорошем месте (как показывает результат), а простой код C выполняет тот же результат (я не нашел InputStream.available, как метод в C для FD, поэтому я не вижу, сколько байтов доступно в поток, но его ожидание вечно)

Что я не так?

+0

Если я дам положительный тайм-аут, его развязали, просыпайтесь бесконечно без ожидания. –

ответ

1

В Java_hu_ddsi_java_Native_JUnix_select вам нужно добавить вызов

FD_ZERO(&watch); 

инициализацию вашего fd_set.

Вы также утечка timeout. Вам нужно либо free это после того, как select возвращений или, лучше, просто объявить его в стек

struct timeval timeout; 
timeout.tv_sec = timeout_s; 
timeout.tv_usec = timeout_us; 
return select(max+1, &watch, NULL,NULL,&timeout); 

Существует подобная утечка pointerfor в Java_hu_ddsi_java_Native_JUnix_poll. Использование malloc может быть уместным, поэтому вам может понадобиться free указатели перед возвратом.

+0

FD_ZERO() не решила проблему, но спасибо за советы по управлению памятью :) –

+0

linux select ограничен первыми 1024 файловыми дескрипторами. см. FD_SETSIZE. если вам нужно добавить дескриптор> 1024, все пойдет не так (неопределенное поведение, часто сбой). предпочитают опрос(). –