Новые книги

The Windows Driver Model has two separate but equally important aspects. First, the core model describes the standard structure for device drivers. Second, Microsoft provides a series of bus and class drivers for common types of devices.

The core WDM model describes how device drivers are installed and started, and how they should service user requests and interact with hardware. A WDM device driver must fit into the Plug and Play (PnP) system that lets users plug in devices that can be configured in software.

Microsoft provides a series of system drivers that have all the basic functionality needed to service many standard types of device. The first type of system driver supports different types of bus, such as the Universal Serial Bus (USB), IEEE 1394 (FireWire) and Audio port devices. Other class drivers implement standard Windows facilities such as Human Input Devices (HID) and kernel streaming. Finally, the Still Image Architecture (STI) provides a framework for handling still images, scanners, etc.

These system class drivers can make it significantly easier to write some types of device driver. For example, the USB system drivers handle all the low-level communications across this bus. A well defined interface is made available to other drivers. This makes it fairly straightforward to issue requests to the USB bus.
Данное учебное пособие подготовлено на основе курса лекций по дисциплине «Нейроинформатика», читавшегося с 1994 года на факультете Информатики и вычислительной техники Красноярского государственного технического университета.

Несколько слов о структуре пособия. Далее во введении приведены

по данному курсу,

. Следующие главы содержат одну или несколько лекций. Материал, приведенный в главах, несколько шире того, что обычно дается на лекциях. В приложения вынесены описания программ, используемых в данном курсе (

и

), и

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

#AutBody_1prog

учебный план

#AutBody_1lab

задания на лабораторные работы

#AutBody_14DocRoot

Clab

#AutBody_15DocRoot

Нейроучебник

#AutBody_16DocRoot

проект стандарта нейрокомпьютера

Данное пособие является электронным и включает в себя программы, необходимые для выполнения лабораторных работ.

Системные вызовы и взаимодействие с UNIX.

6.2.10. Второй пример использования таймера - это таймер, отсчитывающий текущее время суток (а также дату). Чтобы получить значение этого таймера используется вызов функции gettimeofday

    #include <time.h>
    void main(){
            struct timeval timenow;
            gettimeofday(&timenow, NULL);
            printf("%u sec, %u msec\n",
                    timenow.tv_sec,
                    timenow.tv_usec
            );
            printf("%s", ctime(&timenow.tv_sec));
            exit(0);
    }

Поле tv_sec содержит число секунд, прошедшее с полуночи 1 января 1970 года до данного момента; в чем полностью соответствует системному вызову time. Однако плюс к тому поле tv_usec содержит число миллионных долей текущей секунды (значение этого поля всегда меньше 1000000).

6.2.11. К данному параграфу вернитесь, изучив раздел про fork() и exit(). Каждый процесс может пребывать в двух фазах: системной (внутри тела системного вызова - его выполняет для нас ядро операционной системы) и пользовательской (внутри кода самой программы). Время, затраченное процессом в каждой фазе, может быть измеряно системным вызовом times(). Кроме того, этот вызов позволяет узнать суммарное время, затраченное порожденными процессами (порожденными при помощи fork). Системный вызов заполняет структуру

    struct tms {
            clock_t tms_utime;
            clock_t tms_stime;
            clock_t tms_cutime;
            clock_t tms_cstime;
    };

и возвращает значение

    #include <sys/times.h>
    struct tms time_buf;
    clock_t real_time = times(&time_buf);

Все времена измеряются в "тиках" - некоторых долях секунды. Число тиков в секунде можно узнать таким системным вызовом (в системе Solaris):

    #include <unistd.h>
    clock_t HZ = sysconf(_SC_CLK_TCK);

В старых системах, где таймер работал от сети переменного тока, это число получалось равным 60 (60 Герц - частота сети переменного тока). В современных системах это 100. Поля структуры содержат:

tms_utime

время, затраченное вызывающим процессом в пользовательской фазе.

tms_stime

время, затраченное вызывающим процессом в системной фазе.

tms_cutime

время, затраченное порожденными процессами в пользовательской фазе: оно равно сумме всех tms_utime и tms_cutime порожденных процессов (рекурсивное суммирование).

tms_cstime

время, затраченное порожденными процессами в системной фазе: оно равно сумме всех tms_stime и tms_cstime порожденных процессов (рекурсивное суммирование).

real_time

время, соответствующее астрономическому времени системы. Имеет смысл мерять только их разность.

Вот пример программы:

    #include <stdio.h>
    #include <unistd.h>     /* _SC_CLK_TCK */
    #include <signal.h>     /* SIGALRM */
    #include <sys/time.h>   /* не используется */
    #include <sys/times.h>  /* struct tms */
    struct tms tms_stop,  tms_start;
    clock_t    real_stop, real_start;
    clock_t HZ;     /* число ticks в секунде */
    /* Засечь время момента старта процесса */
    void hello(void){
            real_start = times(&tms_start);
    }
    /* Засечь время окончания процесса */
    void bye(int n){
            real_stop = times(&tms_stop);
    #ifdef CRONO
            /* Разность времен */
            tms_stop.tms_utime -= tms_start.tms_utime;
            tms_stop.tms_stime -= tms_start.tms_stime;
    #endif
            /* Распечатать времена */
            printf("User   time          = %g seconds [%lu ticks]\n",
              tms_stop.tms_utime / (double)HZ, tms_stop.tms_utime);
            printf("System time          = %g seconds [%lu ticks]\n",
              tms_stop.tms_stime / (double)HZ, tms_stop.tms_stime);
            printf("Children user   time = %g seconds [%lu ticks]\n",
              tms_stop.tms_cutime / (double)HZ, tms_stop.tms_cutime);
            printf("Children system time = %g seconds [%lu ticks]\n",
              tms_stop.tms_cstime / (double)HZ, tms_stop.tms_cstime);
            printf("Real time            = %g seconds [%lu ticks]\n",
              (real_stop - real_start) / (double)HZ, real_stop - real_start);
            exit(n);
    }
    /* По сигналу SIGALRM - завершить процесс */
    void onalarm(int nsig){
            printf("Выход #%d ================\n", getpid());
            bye(0);
    }
    /* Порожденный процесс */
    void dochild(int n){
            hello();
            printf("Старт #%d ================\n", getpid());
            signal(SIGALRM, onalarm);
            /* Заказать сигнал SIGALRM через 1 + n*3 секунд */
            alarm(1 + n*3);
            for(;;){}       /* зациклиться в user mode */
    }
    #define NCHLD 4
    int main(int ac, char *av[]){
            int i;
            /* Узнать число тиков в секунде */
            HZ = sysconf(_SC_CLK_TCK);
            setbuf(stdout, NULL);
            hello();
            for(i=0; i < NCHLD; i++)
                    if(fork() == 0)
                            dochild(i);
            while(wait(NULL) > 0);
            printf("Выход MAIN =================\n");
            bye(0);
            return 0;
    }

и ее выдача:

    Старт #3883 ================
    Старт #3884 ================
    Старт #3885 ================
    Старт #3886 ================
    Выход #3883 ================
    User   time          = 0.72 seconds [72 ticks]
    System time          = 0.01 seconds [1 ticks]
    Children user   time = 0 seconds [0 ticks]
    Children system time = 0 seconds [0 ticks]
    Real time            = 1.01 seconds [101 ticks]
    Выход #3884 ================
    User   time          = 1.88 seconds [188 ticks]
    System time          = 0.01 seconds [1 ticks]
    Children user   time = 0 seconds [0 ticks]
    Children system time = 0 seconds [0 ticks]
    Real time            = 4.09 seconds [409 ticks]
    Выход #3885 ================
    User   time          = 4.41 seconds [441 ticks]
    System time          = 0.01 seconds [1 ticks]
    Children user   time = 0 seconds [0 ticks]
    Children system time = 0 seconds [0 ticks]
    Real time            = 7.01 seconds [701 ticks]
    Выход #3886 ================
    User   time          = 8.9 seconds [890 ticks]
    System time          = 0 seconds [0 ticks]
    Children user   time = 0 seconds [0 ticks]
    Children system time = 0 seconds [0 ticks]
    Real time            = 10.01 seconds [1001 ticks]
    Выход MAIN =================
    User   time          = 0.01 seconds [1 ticks]
    System time          = 0.04 seconds [4 ticks]
    Children user   time = 15.91 seconds [1591 ticks]
    Children system time = 0.03 seconds [3 ticks]
    Real time            = 10.41 seconds [1041 ticks]

Обратите внимание, что 72+188+441+890=1591 (поле tms_cutime для main).

6.2.12. Еще одна программа: хронометрирование выполнения другой программы. Пример:

timer ls -l
    /* Хронометрирование выполнения программы */
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/times.h>
    extern errno;
    typedef struct _timeStamp {
            clock_t real_time;
            clock_t cpu_time;
            clock_t child_time;
            clock_t child_sys, child_user;
    } TimeStamp;
    TimeStamp TIME(){
            struct tms tms;
            TimeStamp  st;
            st.real_time  = times(&tms);
            st.cpu_time   = tms.tms_utime +
                            tms.tms_stime +
                            tms.tms_cutime +
                            tms.tms_cstime;
            st.child_time = tms.tms_cutime +
                            tms.tms_cstime;
            st.child_sys  = tms.tms_cstime;
            st.child_user = tms.tms_cutime;
            return st;
    }
    void PRTIME(TimeStamp start, TimeStamp stop){
            clock_t HZ = sysconf(_SC_CLK_TCK);
            clock_t real_time  = stop.real_time  - start.real_time;
            clock_t cpu_time   = stop.cpu_time   - start.cpu_time;
            clock_t child_time = stop.child_time - start.child_time;
            printf("%g real, %g cpu, %g child (%g user, %g sys), %ld%%\n",
                    real_time       / (double)HZ,
                    cpu_time        / (double)HZ,
                    child_time      / (double)HZ,
                    stop.child_user / (double)HZ,
                    stop.child_sys  / (double)HZ,
                    (child_time * 100L) / (real_time ? real_time : 1)
            );
    }
    TimeStamp start, stop;
    int main(int ac, char *av[]){
            char *prog = *av++;
            if(*av == NULL){
                    fprintf(stderr, "Usage: %s command [args...]\n", prog);
                    return(1);
            }
            start = TIME();
            if(fork() == 0){
                    execvp(av[0], av);
                    perror(av[0]);
                    exit(errno);
            }
            while(wait(NULL) > 0);
            stop = TIME();
            PRTIME(start, stop);
            return(0);
    }

6.3. Свободное место на диске.

6.3.1. Системный вызов ustat() позволяет узнать количество свободного места в файловой системе, содержащей заданный файл (в примере ниже - текущий каталог):

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <ustat.h>
    struct stat st; struct ustat ust;
    void main(int ac, char *av[]){
         char *file = (ac==1 ? "." : av[1]);
         if( stat(file, &st) < 0) exit(1);
         ustat(st.st_dev, &ust);
         printf("На диске %*.*s\n"
           "%ld свободных блоков (%ld Кб)\n"
           "%d свободных I-узлов\n",
         sizeof ust.f_fname, sizeof ust.f_fname,
         ust.f_fname, /* название файловой системы (метка) */
         ust.f_tfree, /* блоки по 512 байт */
        (ust.f_tfree * 512L) / 1024,
         ust.f_tinode );
    }

Обратите внимание на запись длинной строки в printf: строки, перечисленные последовательно, склеиваются ANSI C компилятором в одну длинную строку:

    char s[] = "This is"  " a line "  "of words";
            совпадает с
    char s[] = "This is a line of words";

6.3.2. Более правильно, однако, пользоваться сисвызовом statvfs - статистика по виртуальной файловой системе. Рассмотрим его в следующем примере: копирование файла с проверкой на наличие свободного места.

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdarg.h>
    #include <fcntl.h>              /* O_RDONLY */
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/statvfs.h>
    #include <sys/param.h>          /* MAXPATHLEN */
    char *progname;                 /* имя программы */
    void error(char *fmt, ...){
            va_list args;
            va_start(args, fmt);
            fprintf(stderr, "%s: ", progname);
            vfprintf(stderr, fmt, args);
            fputc('\n', stderr);
            va_end(args);
    }
    int copyFile(char *to, char *from){       /* куда, откуда */
            char newname[MAXPATHLEN+1];
            char answer[20];
            struct stat stf, stt;
            int fdin, fdout;
            int n, code = 0;
            char iobuf[64 * 1024];
            char *dirname = NULL, *s;
            if((fdin = open(from, O_RDONLY)) < 0){
                    error("Cannot read %s", from);
                    return (-1);
            }
            fstat(fdin, &stf);
            if((stf.st_mode & S_IFMT) == S_IFDIR){
                    close(fdin);
                    error("%s is a directory", from);
                    return (-2);
            }
            if(stat(to, &stt) >= 0){
                    /* Файл уже существует */
                    if((stt.st_mode & S_IFMT) == S_IFDIR){
                            /* И это каталог */
                            /* Выделить последнюю компоненту пути from */
                            if((s = strrchr(from, '/')) && s[1])
                                    s++;
                            else    s = from;
                            dirname = to;
                            /* Целевой файл - файл в этом каталоге */
                            sprintf(newname, "%s/%s", to, s);
                            to = newname;
                            if(stat(to, &stt) < 0)
                                    goto not_exist;
                    }
                    if(stt.st_dev == stf.st_dev && stt.st_ino == stf.st_ino){
                            error("%s: cannot copy file to itself", from);
                            return (-3);
                    }
                    switch(stt.st_mode & S_IFMT){
                    case S_IFBLK:
                    case S_IFCHR:
                    case S_IFIFO:
                            break;
                    default:
                            printf("%s already exists, overwrite ? ", to);
                            fflush(stdout);
                            *answer = '\0';
                            gets(answer);
                            if(*answer != 'y'){     /* NO */
                                    close(fdin);
                                    return (-4);
                            }
                            break;
                    }
            }
    not_exist:
            printf("COPY %s TO %s\n", from, to);
            if((stf.st_mode & S_IFMT) == S_IFREG){
                    /* Проверка наличия свободного места в каталоге dirname */
                    struct statvfs fs;
                    char tmpbuf[MAXPATHLEN+1];
                    if(dirname == NULL){
                            /* То 'to' - это имя файла, а не каталога */
                            strcpy(tmpbuf, to);
                            if(s = strrchr(tmpbuf, '/')){
                                    if(*tmpbuf != '/' || s != tmpbuf){
                                            /* Имена "xxx"
                                             * и второй случай:
                                             * абсолютные имена не в корне,
                                             * то есть не "/" и не "/xxx"
                                             */
                                            *s = '\0';
                                    }else{
                                            /* "/" или "/xxx" */
                                            if(s[1]) s[1] = '\0';
                                    }
                                    dirname = tmpbuf;
                            } else  dirname = ".";
                    }
                    if(statvfs(dirname, &fs) >= 0){
                            size_t size = (geteuid() == 0 ) ?
                                    /* Доступно суперпользователю: байт */
                                    fs.f_frsize * fs.f_bfree :
                                    /* Доступно обычному пользователю: байт */
                                    fs.f_frsize * fs.f_bavail;
                            if(size < stf.st_size){
                               error("Not enough free space on %s: have %lu, need %lu",
                                      dirname, size, stf.st_size);
                               close(fdin);
                               return (-5);
                            }
                    }
            }
            if((fdout = creat(to, stf.st_mode)) < 0){
                    error("Can't create %s", to);
                    close(fdin);
                    return (-6);
            } else {
                    fchmod(fdout, stf.st_mode);
                    fchown(fdout, stf.st_uid, stf.st_gid);
            }
            while (n = read (fdin, iobuf, sizeof iobuf)) {
                    if(n < 0){
                            error ("read error");
                            code = (-7);
                            goto done;
                    }
                    if(write (fdout, iobuf, n) != n) {
                            error ("write error");
                            code = (-8);
                            goto done;
                    }
            }
    done:
            close (fdin);
            close (fdout);
            /* Проверить: соответствует ли результат ожиданиям */
            if(stat(to, &stt) >= 0 && (stt.st_mode & S_IFMT) == S_IFREG){
                    if(stf.st_size < stt.st_size){
                            error("File has grown at the time of copying");
                    } else if(stf.st_size > stt.st_size){
                            error("File too short, target %s removed", to);
                            unlink(to);
                            code = (-9);
                    }
            }
            return code;
    }
    int main(int argc, char *argv[]){
            int i, code = 0;
            progname = argv[0];
            if(argc < 3){
                    error("Usage: %s from... to", argv[0]);
                    return 1;
            }
            for(i=1; i < argc-1; i++)
                    code |= copyFile(argv[argc-1], argv[i]) < 0 ? 1 : 0;
            return code;
    }

Возвращаемая структура struct statvfs содержит такие поля (в частности):

    Типа long:
    f_frsize                размер блока
    f_blocks                размер файловой системы в блоках
    f_bfree                 свободных блоков (для суперпользователя)
    f_bavail                свободных блоков (для всех остальных)
    f_files                 число I-nodes в файловой системе
    f_ffree                 свободных I-nodes (для суперпользователя)
    f_favail                свободных I-nodes (для всех остальных)
    Типа char *
    f_basetype              тип файловой системы: ufs, nfs, ...

По два значения дано потому, что операционная система резервирует часть файловой системы для использования ТОЛЬКО суперпользователем (чтобы администратор смог распихать файлы в случае переполнения диска, и имел резерв на это). ufs - это UNIX file system из BSD 4.x

© Copyright А. Богатырев, 1992-95
Си в UNIX

Назад | Содержание | Вперед