Выбрать и опрос не работает правильно

Я пишу автоматический мультиплексор потока в Java, который должен прочитать большое количество FileDescriptors. Чтобы прочитать файловые дескрипторы (или сокеты и т. Д., Которые имеют FileDescriptor), мне нужна точная подсказка, если у меня есть несколько дескрипторов и нет события, не повторяйте все trout. И вот метод сом в Linux: выберите, опрос. Я пытался использовать эти методы, но безуспешно. родные коды это:

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

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

Иногда код сходит с ума и печатается бездумно:

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

этот результат интересен, fileDescriptor такой же, собственный опрос возвращается с измененными номерами fd, но в структуре pollfd поле revent... должно быть изменено, если произошло событие. Я проверял, указатели находятся в хорошем месте (как показывает результат), и простой код на C дает тот же результат (я не нашел InputStream.available, как метод в C для FD, поэтому я не вижу, сколько байтов доступно в потоке, но ее ждут вечно)

Что я не прав?

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 указатели до возвращения.

Другие вопросы по тегам