Ошибки из-за неправильного обращения

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

В этой главе рассматривается некоторых ошибок, которые Вы могли бы видеть при разработке приложения, использующего Набор I/O для доступа к аппаратным средствам в системе OS X. Это описывает, как «считать» коды ошибки Набора I/O и затем предоставляет некоторую информацию об ошибке эксклюзивного доступа.

Интерпретация Ошибочных Возвращаемых значений Набора I/O

Поскольку Вы будете использовать функции Набора I/O экстенсивно при поиске устройств в Реестре I/O и исследовании объектов, представляющих их, необходимо быть знакомы со структурой ошибочных возвращаемых значений Набора I/O. В этом разделе описывается Ваше приложение может интерпретировать ошибочные значения, возвращенные функциями Набора I/O.

Набор I/O использует ошибочный механизм возврата, определенный платформой ядра, в которой 32-разрядное, возвращаемое значение без знака предоставляет информацию в трех отдельных битовых полях, как показано на рисунке 5-1. Это:

Работать с этими ошибочными возвращаемыми значениями, заголовочным файлом IOReturn.h определяет следующий тип:

typedef kern_return_t IOReturn;    //kern_return_t is an int

Можно использовать kern_return_t и IOReturn получить возвращаемые значения из функций Набора I/O то использование любой тип.

Изобразите  расположение на 5-1 бит для ядра и ошибочных возвращаемых значений Набора I/O
Bit layout for kernel and I/O Kit error return values

Перечисление 5-1 показывает некоторые ошибочные значения общей системы, определяющиеся в заголовке Kernel.framework/Headers/mach/error.h.

Перечисление 5-1  значения системной ошибки Error.h

#define     err_kern    err_system(0x0)     /* kernel */
#define     err_us      err_system(0x1)     /* user space library */
#define     err_server  err_system(0x2)     /* user space servers */
#define     err_ipc     err_system(0x3)     /* old ipc errors */
#define     err_mach_ipc err_system(0x4)    /* mach-ipc errors */
#define     err_dipc    err_system(0x7)     /* distributed ipc */
#define     err_local   err_system(0x3e)    /* user defined errors */
#define     err_ipc_compat err_system(0x3f) /* (compatibility) mach-ipc errors */
#define     err_max_system 0x3f

Этот заголовок также определяет макросы для определения системы и ошибочных значений подсистемы и для извлечения системы, подсистемы и значений кодов от ошибочного возвращаемого значения, как показано в Перечислении 5-2.

Перечисление 5-2  макросы Error.h для работы с ошибочными возвращаемыми значениями

#define     err_system(x)       (((x)&0x3f)<<26)
#define     err_sub(x)          (((x)&0xfff)<<14)
 
#define     err_get_system(err) (((err)>>26)&0x3f)
#define     err_get_sub(err)    (((err)>>14)&0xfff)
#define     err_get_code(err)   ((err)&0x3fff)

Дополнительные системные значения, а также подсистема и значения кодов, определяются в заголовочных файлах для определенных систем. Например, заголовочный файл Kernel.framework/Headers/IOKit/IOReturn.h определяет значения, показанные в Перечислении 5-3 для Набора I/O.

Перечисление 5-3  ошибочные возвращаемые значения IOReturn.h

#ifndef sys_iokit
#define sys_iokit                   err_system(0x38)
#endif /* sys_iokit */
#define sub_iokit_common            err_sub(0)
#define sub_iokit_usb               err_sub(1)
#define sub_iokit_firewire          err_sub(2)
#define sub_iokit_reserved          err_sub(-1)
#define iokit_common_err(return)    (sys_iokit|sub_iokit_common|return)
 
#define kIOReturnSuccess         KERN_SUCCESS            // OK
#define kIOReturnError           iokit_common_err(0x2bc) // general error
#define kIOReturnNoMemory        iokit_common_err(0x2bd) // can't allocate memory
#define kIOReturnNoResources     iokit_common_err(0x2be) // resource shortage
#define kIOReturnIPCError        iokit_common_err(0x2bf) // error during IPC
#define kIOReturnNoDevice        iokit_common_err(0x2c0) // no such device
// ... (many more individual error codes)

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

IOReturn returnVal;
 
returnVal = IOKitSomeFunction(...);
 
if (returnVal == kIOReturnNoDevice)
{
    // "No device returned" error in I/O Kit system, common subsystem.
}

Однако в некоторых случаях можно хотеть изолировать значение кода ошибки или определить, из какой системы или подсистемы ошибочное значение прибыло. Из определений, показанных в Перечислении 5-3, и немного вычисления, Вы видите что ошибочное возвращаемое значение ни для какой ошибки устройства (kIOReturnNoDevice) в системе Набора I/O и Наборе I/O общая подсистема имела бы следующие значения битового поля:

Полностью собранное разрядное представление 1110 0000 0000 0000 0000 0010 1011 1100, получающийся в шестнадцатеричном значении 0xe00002c0. Для извлечения системы, подсистемы или значения кода от такого ошибочного возвращаемого значения, Вы используете макросы, показанные в Перечислении 5-2 вместе с константами, определенными в Перечислении 5-3. Например:

IOReturn returnVal;
 
returnVal = IOKitSomeFunction(...);
 
if (err_get_system(returnVal) == err_get_system(sys_iokit))
{
    // The error was in the I/O Kit system
    UInt32 codeValue = err_get_code(returnVal);
    // Can now perform test on error code, display it to user, or whatever.
}

Обработка ошибок эксклюзивного доступа

Много типов устройств разработаны, чтобы позволить только одному процессу за один раз получать доступ к устройству. Сканер, например, поддерживает доступ только одним приложением за один раз. Соответственно, семьи I/O Kit осуществляют политику доступа для своих устройств, или монопольный или совместно используемый. Кроме того, Классика (Mac OS 9 сред, которые можно выполнить в OS X) может ожидать, что его драйверы будут иметь эксклюзивный доступ к некоторым устройствам, таким как USB-устройства. В ходе разработки приложения, что аппаратные средства доступов, можно получить ошибку эксклюзивного доступа, даже когда Вы верите, Ваш - единственный процесс, пытающийся открыть устройство. Когда это происходит, если нет никакого высокоуровневого арбитража, который можно нанять, Вы, возможно, должны представить диалоговое окно пользователю и или попытаться получить доступ к другому устройству того же класса или попытаться получить доступ к тому же устройству позже или при различных обстоятельствах.

Определенный в IOReturn.h (в платформе Набора I/O), kIOReturnExclusiveAccess ошибка говорит Вашему приложению, что устройство, к которому это пытается получить доступ, было уже открыто другим объектом. В большинстве случаев пользовательский клиент осуществляет эксклюзивный доступ в open метод. Когда приложение использует интерфейс устройства open функция, интерфейс устройства выходит open команда пользовательскому клиенту. Пользовательский клиент отвечает путем попытки открыть его провайдера (кусок устройства) и, если он перестал работать, он возвращается kIOReturnExclusiveAccess ошибка. (Если пользовательский клиент найдет, что провайдер завершается, то он, вероятно, возвратится kIOReturnNotAttached ошибка.)

Различные семейства устройства Набора I/O обрабатывают проблему эксклюзивного доступа по-разному. Семья FireWire, например, осуществляет эксклюзивный доступ к своим устройствам, но также и позволяет многократным интерфейсам устройства открывать различные объекты в штабеле драйвера FireWire. Это делает это путем использования понятия ссылки сеанса для обращения к существующим соединениям ядра пространства пользователя. Рассмотрите заявление, использующее интерфейс устройства семьи FireWire для открытия модуля AV/C на устройстве FireWire. Если то приложение также хочет получить доступ к объекту модуля FireWire, поддерживающему модуль AV/C, это может получить ссылку сеанса от интерфейса устройства AV/C и использовать его для получения интерфейса устройства модуля FireWire. Для получения дополнительной информации об этом процессе посмотрите Руководство по Интерфейсу Устройства FireWire.

Семья Model архитектуры SCSI, с другой стороны, не позволяет многократным интерфейсам устройства одновременно открывать различные объекты в штабеле драйвера, но это действительно позволяет приложениям получать информацию об устройствах, в драйверах ядра в настоящее время имеющих открытый. Это также позволяет приложению получать эксклюзивный доступ к авторской разработке или осваивающему носители устройству, разъединяя верхние уровни штабеля и требуя, чтобы драйвер логической единицы в ядре привел к управлению приложению. Для получения дополнительной информации об этом процессе, посмотрите Руководство по Интерфейсу Устройства модели архитектуры SCSI.

Для последовательных устройств и устройств хранения можно получить доступ через файлы устройств, приложение может не открыть устройство по следующим причинам: