Макросы FD_SET и FD_ISSET, написанные на javascript

Мы с другом работали над этим некоторое время назад. Он предназначен для использования с js-ctypes. В Linux есть эти макросы для работы с добавлением списка файловых дескрипторов (uint32) в байтовый массив: FD_SET и FD_IS_SET. Документы находятся здесь - http://linux.die.net/man/2/select

Мне было интересно, сможет ли кто-нибудь проверить, правильно ли я это сделал, или кто-нибудь знает кого-нибудь, кто сделал это в javascript? Мне нужно завершить 32-битную / 64-битную поддержку для прямого и прямого порядка байтов, но если она уже существует, я бы хотел ее увидеть, поскольку, когда мы работали над этим, у нас было так много неопределенностей.

Вот код, fd_set_get_idx была вспомогательной функцией, на которой все это основано.

var MACROS = {
        fd_set_set: function(fdset, fd) {
            let { elem8, bitpos8 } = MACROS.fd_set_get_idx(fd);
            console.info('elem8:', elem8.toString());
            console.info('bitpos8:', bitpos8.toString());
            fdset[elem8] = 1 << bitpos8;
        },
        fd_set_isset: function(fdset, fd) {
            let { elem8, bitpos8 } = MACROS.fd_set_get_idx(fd);
            console.info('elem8:', elem8.toString());
            console.info('bitpos8:', bitpos8.toString());
            return !!(fdset[elem8] & (1 << bitpos8));
        },
  fd_set_get_idx: function(fd) {
            if (osname == 'darwin' /*is_mac*/) {
                // We have an array of int32. This should hopefully work on Darwin
                // 32 and 64 bit.
                let elem32 = Math.floor(fd / 32);
                let bitpos32 = fd % 32;
                let elem8 = elem32 * 8;
                let bitpos8 = bitpos32;
                if (bitpos8 >= 8) {     // 8
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 16
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 24
                    bitpos8 -= 8;
                    elem8++;
                }

                return {'elem8': elem8, 'bitpos8': bitpos8};
            } else { // else if (osname == 'linux' /*is_linux*/) { // removed the else if so this supports bsd and solaris now
                // :todo: add 32bit support
                // Unfortunately, we actually have an array of long ints, which is
                // a) platform dependent and b) not handled by typed arrays. We manually
                // figure out which byte we should be in. We assume a 64-bit platform
                // that is little endian (aka x86_64 linux).
                let elem64 = Math.floor(fd / 64);
                let bitpos64 = fd % 64;
                let elem8 = elem64 * 8;
                let bitpos8 = bitpos64;
                if (bitpos8 >= 8) {     // 8
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 16
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 24
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 32
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 40
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 48
                    bitpos8 -= 8;
                    elem8++;
                }
                if (bitpos8 >= 8) {     // 56
                    bitpos8 -= 8;
                    elem8++;
                }

                return {'elem8': elem8, 'bitpos8': bitpos8};
            }
        }
};

person Noitidart    schedule 19.07.2016    source источник
comment
Что не так со старыми добрыми >>, << и &, |   -  person Antti Haapala    schedule 19.07.2016
comment
Кроме того, можно было бы использовать цикл for...   -  person Antti Haapala    schedule 19.07.2016
comment
Я не могу понять, хотите ли вы просто эмулировать функции FD_XXX или вам нужно соответствовать чему-то. JS, особенно ES6, имеет DataView и типизированные массивы, если вы хотите их использовать. В любом случае, если семантика FD_SET(i, set) - это просто set[i] = i, я не вижу никаких проблем с ее реализацией, с любым порядком байтов или размером, с нуля. Вы можете уточнить? Также это fdset[elem8] = 1 << bitpos8 скорее всего неверно.   -  person Margaret Bloom    schedule 19.07.2016
comment
Большое спасибо @Margaret и Anti - да, мы пытались просто подражать FD_XXX, ничего не согласовывая. Честно говоря, это было много лет назад, и я не могу вспомнить, верна ли эта семантика. Я так не думаю, поскольку, когда я только что использовал это, индекс idx в приведенном выше коде был другим. (именно поэтому я добавил теги для linux и c к этому вопросу. Я знаю, что он может быть закрыт, но мне больше не у кого спросить, кто обладает такими знаниями. Все мои навыки позволяют использовать эти функции)   -  person Noitidart    schedule 19.07.2016


Ответы (1)


Я оставляю на вас бремя определения порядка следования байтов и размера слова.
Приведенный ниже код эмулирует функции FD_XXX и позволяет указать порядок следования байтов и размер слова.

<!doctype>
<html>
    <head>
        <script>
            var SIZE_32 = 4
            var SIZE_64 = 8

            var LITTLE_ENDIAN = [0, 1, 2, 3, 4, 5, 6, 7];
            var BIG_ENDIAN = [7, 6, 5, 4, 3, 2, 1, 0];

            function fdset(setSize, endianness, size)
            {
                var buffer = new Uint8Array(div(setSize + 7, 8));



                function div(a, b)
                {
                    return Math.floor(a / b);
                }

                function make_index(index)
                {
                    return div(index, 8 * size) * size + endianness[div(index % (8 * size), 8)] % size;
                }

                buffer.set_bit = function(index)
                {
                    buffer[make_index(index)] |= 1 << (index % 8);
                };

                buffer.clear_bit = function(index)
                {
                    buffer[make_index(index)] &= ~(index % 8);
                };

                buffer.get_bit = function(index)
                {
                    return buffer[make_index(index)] & 1 << (index % 8);
                };

                buffer.zero = function()
                {
                    buffer.fill(0);
                }


                return buffer;
            }

            function FD_SET(fd, fdset)
            {
                fdset.set_bit(fd);
            }

            function FD_ISSET(fd, fdset)
            {
                return !!fdset.get_bit(fd);
            }

            function FD_CLR(fd, fdset)
            {
                return fdset.clear_bit(fd);
            }

            function FD_ZERO(fdset)
            {
                return fdset.zero();
            }


        </script>
    </head>
    <body>
        <script>
            var s = fdset(128, LITTLE_ENDIAN, SIZE_64);

            //s in an Uint8Array

            console.log(s);

            FD_SET(0, s);    //Byte 0 = 1
            FD_SET(9, s);    //Byte 1 = 2
            FD_SET(18, s);   //Byte 2 = 4
            FD_SET(27, s);   //Byte 3 = 8
            FD_SET(36, s);   //Byte 4 = 16
            FD_SET(45, s);   //Byte 5 = 32
            FD_SET(54, s);   //Byte 6 = 64
            FD_SET(63, s);   //Byte 7 = 128

            FD_SET(120, s);  //Byte 15 = 1
            FD_SET(113, s);  //Byte 14 = 2
            FD_SET(106, s);  //Byte 13 = 4
            FD_SET(99, s);   //Byte 12 = 8
            FD_SET(92, s);   //Byte 11 = 16
            FD_SET(85, s);   //Byte 10 = 32
            FD_SET(78, s);   //Byte 9 = 64
            FD_SET(71, s);   //Byte 8 = 128

            console.log(s);

            //64 bits, BE: [128, 64, 32, 16, 8, 4, 2, 1, 1, 2, 4, 8, 16, 32, 64, 128]
            //64 bits, LE: [1, 2, 4, 8, 16, 32, 64, 128, 128, 64, 32, 16, 8, 4, 2, 1]
            //32 bits, BE: [8, 4, 2, 1, 128, 64, 32, 16, 16, 32, 64, 128, 1, 2, 4, 8]
            //32 bits, LE: [1, 2, 4, 8, 16, 32, 64, 128, 128, 64, 32, 16, 8, 4, 2, 1]
        </script>
    </body>
</html>

Функция fdset возвращает Uint8Array, который вы можете передать нативной функции или уточнить.
setSize задает максимальный поддерживаемый файловый дескриптор.


Обратите внимание, что js ctypes уже имеет тип массива и обычные типы [U]intXX_t в собственном порядке байтов, увы, нет типа, который сопоставляется с 32/64-битными целыми числами на основе платформы, и нет sizeof оператор2, поэтому вам все равно нужно выполнить внешнюю проверку для определения размера слова.

Использование ctypes было бы более естественным.
Для справки: здесь представлена ​​официальная реализация функций FD_XXX.

Вы можете определить структуру с одно поле типа массив из uint32/64_t.
Затем имитируйте поведение исходного кода C, стараясь использовать UInt64 при необходимости1 и избегая смен.


1 В JS есть только двойные числа, эти числа имеют 53 бита мантиссы, 10 бит экспоненты и 1 бит знака. Когда используются битовые операторы, двойное число преобразуется в целое число, поскольку именно мантисса определяет точность (показатель степени — это просто шкала, знак — просто инверсия), это число может нести не больше информации, чем 53 бита. количество.

2 Насколько мне известно, я совсем не эксперт в js ctypes.

person Margaret Bloom    schedule 19.07.2016
comment
Вау, искреннее спасибо за это усилие! Я помню, как в последний раз, когда я работал над этим, я утонул в чтении этих ссылок - - Сейчас я проверю ваш код! :) - person Noitidart; 19.07.2016
comment
@Noitidart Добро пожаловать. Дважды проверьте это, я не уверен, что действительно понял ваши потребности! - person Margaret Bloom; 19.07.2016
comment
Должен признаться, я на самом деле понятия не имел, что делает приведенный выше код. Я скопировал его из другого проекта js-ctypes. Я сформулировал это так, как будто я сделал это с другом, потому что я волновался, что это закроют, и я не мог найти никакой помощи. Я кодер js, который может портировать материал C на js, если это 1-к-1. Я не понимаю endianess, 32-битные и 64-битные вещи. Хотели бы вы когда-нибудь получить 30 минут бесплатно, чтобы использовать чат stackoverflow об этом коде? Я использую его в ctypes, поэтому я передаю его на реальную платформу C apis, поэтому буфер — это то, что мне нужно. Но я запутался с самого начала, в том числе в настройке размера. :( - person Noitidart; 19.07.2016
comment
@Noitidart Я сейчас на работе. Отредактируйте вопрос, указав все детали, которые, по вашему мнению, важны. Я обновлю свой ответ, если найду решение :) - person Margaret Bloom; 19.07.2016
comment
Большое спасибо, Маргарет. Мой главный вопрос: если у меня есть X число fd, а самый большой fd - это Y, как я могу определить размер для использования. Место, откуда я украл это много лет назад, показало мне, как использовать оригинал — github.com/Noitidart/jscFileWatcher/blob/master/ - person Noitidart; 19.07.2016
comment
@Noitidart Вы можете думать о FDSET как о наборе, который может содержать все дескрипторы от 0 до setSize. Просто передача Y вместо setSize должна помочь. - person Margaret Bloom; 19.07.2016
comment
Большое спасибо! Другой вопрос, который у меня был, заключался в том, что в оригинале он делал разные вещи, потому что в его комментариях говорилось, что в Linux это длинные целые числа, потому что я делаю это в ctypes, тип имеет значение, означает ли это, что между байтами должно быть дополнение? В комментариях он сказал, что ему нужно добавить 32-битную поддержку, я думаю, что в 64-битном это 64-битное число, а в 32-битном - 32-битное, мне было интересно, как это будет отличаться. В ctypes 64-битное число — это просто его строка, поскольку js не может превышать 53 бита (я тоже не понимаю этих битов, лол) - person Noitidart; 19.07.2016
comment
@Noitidart Я просмотрел исходный код Linux для реализации FD_XXX. Он эффективно использует массив unsigned long, а не байтов. Я напишу новый ответ позже, так как это приводит к порядку байтов и размеру слова. Пожалуйста, отмените этот ответ, чтобы я мог удалить его. Спасибо :) - person Margaret Bloom; 19.07.2016
comment
Вау, искреннее спасибо @Margaret за вашу потрясающую помощь. Год назад я написал просьбу о помощи, но ничего не получил. Я любитель, но я делаю некоторые полезные вещи, которые нравятся людям, я использую это для подмодуля просмотра файлов в дополнениях Firefox, глупые люди не помогают мне с PR или объяснениями, хотя, ха-ха. Но они говорят, что очень ждут, когда я закончу, чтобы использовать его!!! - person Noitidart; 20.07.2016