Vemos char drivers porque son los dispositivos de hardware mas simples,
El primer paso cuando escribimos un driver es definir las funcionalidades(mecanismo) que el driver le ofrese a sus usuarios.

MAJOR and MINOR numbers:
Accedemos a los dispositivos de caracteres mediante nombres en el filesystem (device files o nodos del fs. EJ: /dev/*)

Los char drivers son identificados con una c (y los block drivers con una b) cuando hacemos un ls -l /dev/.

Tambien vemos dos numeros separados por como, estos son el MAJOR y el MINOR number de cada dispositivo.

Minor y Major
MAJOR -> identifica el driver asociado al dispositivo (EJ: /dev/null y /dev/zero -> driver 1)

MINOR -> es usado por el kernel para determinar exactamente que dispositivo se esta referenciando.

Dependiendo de como escribamos el driver podemos obtener un puntero del kernel al dispositivo o podemos usar MINOR para tener un indice local de un array de dispositivos.

REPERESENTACION interna de los device numebers:

En el kernel tenemos el tipo dev_t (definido en <linux/types.h) que es usado para almacenar los device numbers. Tenemos macro para setear estos numeros (MAJOR(dev_t dev) y MINOR(dev_t dev)) -> Obtenemos (le pedimos al kernel) un numero de dispositivo.

Si ya los tenemos y los queremos asignar:
mkdev(int major, int minor)

RESERVANDO y liberando device numbers:
una de las primeras cosas que nuestro driver a a tener que hacer a la hora de configurar cada char device es obtener uno o mas device numbers para trabajar. La funcion necesaria para hacer esto es:

int register_chrdev_region(dev_t first, unsigned int count, char *name)

Donde first es el primero de un rango de device numbers que queremos obtener. El MINOR de first por lo general es 0. Y count es el numero total de device numbers contiguos que queremos obtener. Finalmente name es el nombre asociado a este rango de numeros que aparecer en /proc/devices y sysfs

register_chrdev_region funciona bien si sabemos de antemano que device numbers queremos. Generalmente no sabemos que major number usara nuestro dispositivo.
Para esta situaciones el kernel on the fly alloca major numbers con:

int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name)

En esta funcion dev es un parametro de salida que cuando se completa la operacion tiene el primer numero del rango allocado.

Los device numbers son liberados con:
void unregister_chrdev_region(dev_t first,unsigned int count)

Por lo general lo llamamos en la funcion de clean up (la marcada con __exit).
Estas funciones allocan los device numbers para que los usuemos per ono le dicen nada al kernel acerca de que vamos a hacer con estos numeros. Antes de que una aplicacion de usuario pueda hacer uso de un device number, el driver tiene que conectarse con sus funciones internas que implementan las operacion del dispositivo.

ALLOCACION dinamica de los major numbers:

ALgunos de los major device numbers son asignados a los dispositivos mas comunes (documentation/devices.txt). Por lo tanto podemos escoger para nuestro dispositivo un numero que paresca no estar usandose, o podemos allocar major numbers de manera dinamica. (para drivers nuevos siempre usamos alloc_chrdev_region). La desventaja de la allocacion dinamica es que no podemos crear los nodos del dispositivo por adelantado. En situaciones normales esto es rara vez un problema, ya que podemos leer los device numbers en /proc/devices. Entonces en vez de llamar solamente a insmod, llamamos a un script que llama a insmod, lee de /proc/devices y luego crea los nodos.

Allocacion dinamica

ALGUNAS ESTRUCTURAS DE DATOS
Las operaciones fundamentales de los driver involucran 3 estructuras de datos del kernel llamadas: file_operations, file y inode.

FILE_OPERATIONS:
Hasta ahora habiamos reservado algunos device numbers para usar, pero no los habiamos conectado con ninguna operacion de driver. Con la estructura file_operations logramos que un char driver haga esta conexion.
Esta estructura (que esta definida en <linux/fs.h>) es una coleccion de punteros a fc. Cada archivo abierto (representado por una estructura file) es asociado con su propio set de funciones (mediante la inclusion de un campo llamado f_op que apunta a una estructura file_operations).
Las operaciones estan a cargo de la implementacion de las system calls y por esto son llamadas open, read, write, close, etc. Podemos considerar a un archivo como a un objeto y a las funciones que operan sobre el los metodos.

La siguiente lista introduce las operaciones mas importantes que una aplicacion puede llamar sobre un dispositivo:

struct module *owner: no es una operacion, es un puntero al modulo que posee a la estructura. es usado para prevenir que el modulo sea descargado mientras las operaciones se siguen usando.

loff_t (*llseek) (struct file*, loff_t, int): este metodo es usado par acambiar la posicion actual de lectura/escritura en un archivo (la nueva posicion es un entero positivo, negativo si es error)

ssize_t (*read) (struct file*, char __user *, size_t, loff_t *): usado para recoger datos desde el dispositivo. Un resultado positivo nos indica cuantos bytes se leyeron.

ssize_t (*aio_read) (struct kiocb*, char __user* , size_t, loff_t*): indica una lectura asincrona, es decir, que la operacion puede no completarse antes de que la funcion termine. Si este metodo es NULL, todos los read se hacen sincronos.

ssize_t (*write) (struct file* , const char __user*, size_t, loff_t*): envia datos al dispositivo. El valor de retorno si es positivo, es la cantidad de datos que se escribieron exitosamente.

int (*open) (struct inode * , struct file *): esta es siempre la primera operacion realizada sobre el dispositivo.

int (*ioctl) (struct inode*, struct file*, unsigned int, unsigned long): esta llamada ofrece una manera de lidiar con comandos especificos de un dispositivo (formatear un disquette, abrir la lectora, etc, que no son de lectura y escritura). Adicionalmente, algunos pocos comonados ioctl son reconocidos por el kernel sin referirs a la tabla de fops.

File Operations

LA ESTRUCTURA FILE:

La estructura esta definida en <linux/fs.h> es la segunda en importancia de las estructuras de datos utilizadas en los device drivers.
La estructura file representa un archivo abierto. Es creada por el kernel cuando se llama open y es pasada a todas las funciones que operan sobre el archivo hasta el ultimo close.
La siguiente lista muestra los campos mas importantes de la struct file:

mode_t f_mode: identifica si los archivos son de lectura y escritura con una mascara: FMODE_READ y FMODE_WRITE.

loff_t f_pos: indica la posicion actual de lectura y/o escritura. El driver puede leer este valor si necesita saber la posicion en el archivo, pero por lo general, nunca deberia cambiarla. Read y Write deberian actualizar la posicion usando el puntero que reciben como ultimo argumento y no modificando directamente filp->f_pos. La excepcion a esto es el metodo llseek.

struct file_operations *f_op: son las operaciones asociadas al archivo. El valor de filp->f_op nunca es guardado por el kernel, por lo tanto podemos cambiar el comportamiento en runtime solo apuntando a otra estructura.

LA ESTRUCTURA INODE:

Es usada internamente po rle kernel par representar archivos. Es distinta a la estrucutra fule que representa un descriptor de un archivo abierto. Pueden haber muchas estrucutras file representando multiples descriptores abiertos sobre un solo archivo, pero todos ellos apuntan a una sola estructura inode.
La estructura INODE contiene mucha informacion sobre el archivo. Pero solo 2 son de interes a la hora de escribir drivers:

dev_t i_rdev: para inodes que representan archivos de dispositivos, este campo contiene el actual numero de dispositivo.

struct cdev *i_cdev: cdev es la estrucutra interna del kernel que representa a un char device; este campo contiene un puntero a la estrucutra cuando el inode se refiere a un char device. Hay 2 macros para obtener el major y el minor number de un inode:

unsigned int imajor(struct inode *inode)
unsigned int iminor(struct inode *inode)

REGISTRACION DE CHAR DEVICES:

COmo ya vimos el kernel usa la estructura cdev para representar un char device internamente. Antes de que el kernel invoque nuestras operaciones, debemos allocar y registrar una o mas de una de estas estructuras. Para esto incluimos <linux/cdev.h>. Hay 2 maneras de allocar y inicializar una de estas estructuras. Por ejemplo si queremos obtener una standalone cdev structure en runtime lo hacemos con:

struct cdev *my_cdev=cdev_alloc();
my_cdev->ops=&my_fops;

Sin embargo a veces vamos a querer embeber una estrucutra cdev con una estructura especifica del dispositivo que nosotros hayamos llenado. En estos casos debemos inicializar la estrucutra que ya hemos allocado con:

void cdev_init(struct cdev * cdev, struct file_operations *fops);

Igualmente el campo owner de cdev tiene que ser seteado con THIS_MODULE.

Una vez que la estructura ha sido inicializada el paso final es avisarle al kernel.

int cdev_add(struct cdev *dev, dev_t num, unsigned int count)

Donde dev es la estructura cdev, num es el primer devibe number al que el dispositivo responde y count es el numero de debice number que debe ser asociado con el dispositivo.

Hay un par de cosas a tener en mente cuando usamos cdev_add. Lo primer es que puede fallar. Si devuelve un error code negativo, nuestro dispositivo no fue agregado al sistema. Si devuelve exitoso, en ese mismo momento nuestro dispositivo esta vivo y sus operaciones pueden ser llamadas por el kernel.
Para remover un char device del sistema usamos:

void cdev_del(struct cdev *dev)

METODOS OPEN Y RELEASE:

EL METODO OPEN:
Para hacer cualquier cosa inicializamod en orden de estar preparados para futuras operaciones. En la mayoria de los drivers open tiene las siguientes tareas:

Verificar errores especificos de los dispositivos
Inicializar el dispositivo si esta siendo abierto por primera vez
Actualizar el puntro f_op
Allocar y llenar cualquier estructura de datos para ser puesta en filp->private_data

Recordando el prototipo del metodo

int (*open) (struct inode *inode, struct file *filp):

Inode tiene la inofrmacion que necesitamos en la forma de su campo i_cdev que contiene la estructura cdev seteada antes. El probloema es que probablemente en la vida real queramos my_cdev strcutrue que contiene a la estrucutra cdev. Para esto recurrimos a un truquito llamado macro container_of (<linux/kernel.h>)

container_of(pointer, container_type, container_field);
Este marcro toma el puntero a un campo (pointer) del tipo container_field con una estrucutra del tipo Container_type. y retorna un puntero a la estructura contenida.

Ejemplo en scull:

struct scull_dev *dev;
dev=container_of(inode->i_cdev,strcut scull_dev, cdev);
filp->private_data=dev;

EL METODO RELEASE:

El objetivo de release es lo contrario de open y debe realizar las siguientes tareas:

Desallocar todo lo que open alloco en filep->priv_data
Apagar el dispositivo cuando ocurra el ultimo close

El metodo release mediante las llamada del metodo clouse pero solamente cuando el contado de las estructuras file llegue a 0. *en ese momento la estrucutra se destruye). Este contado es llavado por el kernel que cuenta cuantas veces una estructura file esta siendo usada.

USO DE MEMORIA:

2 funciones core definidas en: <linux/slab.h>

void *kmalloc(size_t size, int flags);
void kfree(void *ptr);

una llamda a kamalloc trata de allocar size bytes de memoria; el resultado es un puntero a esa memoria o NULL si falla, El argumento flag es usado para describir como se debe allocar la memoria. (GFP_KERNEL)

METODOS READ Y WRITE:

Estos dos metodos realizan tareas similares,, copian datos de y hacia la aplicacion. Por esto sus prototipos son muy similares:

ssize_t read (struct file *filp, char __user *buff, size_t count, loff_t *offp);

ssize_t write(struct file *filp, const char __user *buff, size_t count, loff *offp);

filp es el file pointer, count es la cantidad de datos requeridos para transferir. Buff apunta al buffer del usuario que contiene los datos para ser escritos o un buffer vacio donde los datos leidos seran puestos. Funalmente offp es un puntero *del tipo long offset type) que nos indica la posicion en el archivo donde esta accediendo el usuario.

Hay que tener en cuenta que el argumento buff de los metodos read y write es un puntero a espacio de usuario. Por lo tanto no puede ser directamente referenciado por codigo del kernel. Hay un par de razsones para esta restriccion:

• Dependiendo en que arquitectura esta corriendo el driver, y como el kernel ha sido configurado, el puntero al espacio de usuario puede no ser valido cuando estamos corriendo en modo kernel, puede que esta direccion no tenga mapeo, o puede que apunte a otros datos random.
• Aun si el puntero sifnifica lo mismo en espacio de kernel, la memoria del espacio de usuario es paginada (swapeable), y puede no encontrarse en RAM, cuando la sys call es hecha. Tratar de acceder directamente a la memoria de espacio de usuario puede generar un page fault, cosa que no esta permitida en el kernel.
• El puntero en cuestion ha sido provisto por el usuario y puede ser buggy o malisioso.

Obiamente igual nuestro driver tiene que poder acceder al buffer de espacio de usuario para realizar su trabajo. Este acceso debe ser realizado siempre por funciones provistas por el kernel para que sea seguro.
Estas funciones son: (<asm/uaccess.h>)

unsigned long copy_to_user(void __user *to, const void* from, unsigned long count);

unsigned long copy_from_user(void *to, const void __user *from, unsigned long count);

A pesar de que estas funciones se comportan como una funcion memcpy hay que tener un cuidado extra cuando accedemos al espacio de usuario desde el kernel.
Ya que las paginas de usuario pueden no estar presentes en memoria y el sistema de memoria virtual puede poner el proceso a dormir.
EL rol de estas funciones no esta limitado a copiar datos del espacio del usuario, sino tambien a revisar que el puntero en espacio de usuario sea valido. Si el puntero no es valido, no se copia nada. Y si se encuentra una direccion no valida durante la copia, solo una parte de los datos es copiada. En los dos casos el valor de retorno es la cantidad de datos copiados.

Entonces la tara del metodo read es copiar del dispositivo al espacio de usuaro (con copy_to_user). Y la tarea del metodo write es copiar datos del espacio de usuario al disposito (con copy_from_user).

Argumentos

Cualquiera sea la cantidad de datos copiados, generalmente hay que actualizar la posicion donde nos encontramos en el archivo(*offp)

EL METODO READ:

el resultado de read es interpretado por la aplicacion que realizo la llamada:

- Si el valor es igual a count => todo OK!
- Si el valor es positivo pero menor a count => solo una parte se copio
- Si el valor es 0 => EOF
- Si el valor es negativo => se produjo un error

El metodo write es igual que el read

y hay que recordar que tenemos writes y read vectoriales

Bienvenidos a Hello World Module:

Hello World! Un clasico!
Importante: 2 funciones:
module_init(fc*)
module_exit(fc*)

Hay que incluir <linux/init.h> y <linux/module.h>

• Modulo de kernel vs Apps
Diferencias:
- En las aplicaciones: por lo general programamos aplicaciones que son una tarea de principio a fin.
- Modulo: por lo general se registran con el fin de servir a futuras peticiones.
Los modulos son event_driven. En los modulos solo podemos usar las propias funciones del kernel. Y no podemos linkear librerias a los modulos. Solo tenemos las funciones en las interfaces del kernel (kernel headers).

Otra diferencia es como se manejan las fallas.
• En las aplicaciones tenemos seg faults, y para solucionar problemas  podemos usar un debugger     convencional
• En los modules de kernel tenemos kernel fault o kernel panic. Y se nos complica usar un debugger.

Espacio de kernel y espacio de usuario:
Aplicacion -> espacio de usuario
Modulo -> espacio de kernel
Se especifican diferentes modalidades o niveles de operaciones en el CPU. Cada nivel tiene asociado un Rol. Y algunas operaciones se ven restringidas en ciertos niveles. El codigo de los programas puede pasar de un nivel a otro(cambio de contexto) por un numero limitado de puertas.

En unix el kernel se ejecuta en el nivel mas alto (supervisor-mode) donde todo esta permitido. Las aplicaciones se corren en un nivel mas bajo (user-mode). Donde el procesador regual el acceso directo al hardware y el acceso sin autorizacion a la memoria.

Unix transfiere la ejecucion de un espacio a otro cuando una aplicacion ejecuta una syscall o cuando una aplicacion es suspendida por una interrupcion.
Concurrencia en el kernel:
Todas las cosas que hagamos tiene que estar concebida con la idea de que muchas cosas ocurren en paralelo al mismo tiempo que la nuestra.

Todo el codigo de un driver tiene que ser reentrante (poseer la capacidad de poder correr en mas de un contexto a la vez). Las estructuras de datos deben ser cuidadosamente diseniadas para mantener multiples hilos de ejecucion separados. Y se debe cuidar mucho el acceso a datos compartidos.

Proceso Actual:

Incluimos: <asm/current.h> y <linux/sched.h> y podemos acceder a una variable llamada current que es del tipo task_struct y contiene toda la informacion del proceso que se esta ejecutando: current->comm (nombre del programa) y current->pid

Compilando modulos:
??????

Ejemplo Make File
 Linkeando modulos al kernel:

Vinculando modulos al kernel
Cargando un modulo:
Insmod, modprobe, rmmod y lsmod (que lee de /proc/modules)
Algunas cosas:
• vermagic.o: esta para chequear si el kernel donde queremos plugguear un modulo es compatible con el modulo compilado
• Se pueden usar macros y #ifdef para hacer el modulo compatible para varias versiones de kernels
• Tambien hay dependencias de plataformas

Tabla de simbolos del kernel:
Insmod resuelve todos los simbolos no definidos contra esta tabla publica de simbolos del kernel.
Esta tabla contiene direcciones de items globales(como funciones y variables) que son necesarias para implementar drivers modulares. Cuando un modulo es cargado, cada simbolo exportado por el modulo se vuelve parte de esta tabla global de simbolos.
export_symbol(name); export_symbol_gpl(name);
Lo usamos normalmente cuando hacemos un stack de modulos que necesitan conocer algunas variables de otros modulos.
Estas variables se situan en una seccion llamada ELF section que es revisada por el kernel cuando el modulo es cargado.

Algunos Conceptos preliminares:
En todos los cmodulos si o si:  <linux/init.h> y <linux/module.h>

Funcion de inicializacion:

static int __init xxx(void){

}
module_init(xxx);

el __init es un hint para el kernel que dice que esta funcion es solamente en tiempo de inicializacion. esto quiere decir que no podemos usarla una vez terminada la fase de inicializacion porque es descartada.

module_init nos dice cual es la funcion que va a ser llamada en tiempo de inicializacion. Agrega a la funcion xxx en una seccion especial del modulo para que apenas se cargue el modulo sea lo primero en ejecutarse.

En este metodo registramos dispositivos y recursos que vayamos a usar en nuestro modulo.

Funcion de limipieza:
static void __exit xxx(void){

}
module_exit(xxx);
sino tenemos esta funcion el kernel no nos permite remover el modulo una vez que esta cargado.

Manejo de errores en la inicializacion:
Si algun error ocurre cuando estamos registrando cosas tenemos que desidir si continuar o no. Seguido, pasa que si algo falla igual continuamos y luego nuestro modulo brinda funcionalidades limitadas.
Si llegamos a un error donde el modulo no va a poder ser cargado, tenemos que deshacer todas las registraciones hehchas antes de la falla. (el modulo debe encargarse de esto, sino el kernel queda en un estado inestable)

Por lo general afrontamos este tema con GOTO:

copiar el ejemplo que estaba mas que interesante;;;;
Inicializacion Limpia

Condiciones de corrida a la hora de cargar los modulos
Hay que tener cuidado con lo que registramos y cuando lo registramos. Tenemos que recordar que en alguna otra parte del kernel puede estar haciendo uso de alguna de las capacidades(facilities) que nosotros registramos justo despues de que la registracion haya terminado.
Entonces: no hay que registrar ninguna funcionalidad hasta que nuestra inicializacion interna para soportar esta funcionalidad se haya completado.
Tambien debemos considerar que pasa si la inicializacion falla pero parte del kernel ya usa esta funcionalidad que hemos registrado. Si esta situacion es posible, debemos considerar en no hacer falla la inicializacion, ya que algo util para alguien ha sido registrado.

Parametros de un modulo:
Muchos parametros que un driver necesita puede cambiar de un sistema a otro.
Los parametros pueden obtener sus valores en tiempo de carga con insmod o modprobe. Y estos parametros pueden ser de varios tipos.
Ej:
insmod hellop howmany=10 whom=’mom’

static char *whom=”world”
static int howmany=1
module_param(howmany,int,S_IRUGO);
module_param(whom,charp,S_IRUGO);

Si hay algun tipo de dato que no sea soportado por module_param, hay un hook que nos permite definirlos. (module_param.h)
S_IRUGO es un permission value(<linux/stat.h>) y controla quien puede acceder a la representacion del parametro en el sysfs. Si es 0 no hay entrada en sysfs, sino aparece en /sys/module
S_IRUGO -> solo lectura
S_IRUGO | S_IWUSR -> escritura  por el root
si lo hacemos de escritura y cambiamos el valor, el modulo no se entera automaticamente de que el valor cambio. Por lo tanto hay que estar preparados para detectar el cambio en el parametro.

Driver en espacio de usuario
Ventajas:
• Podemos linkear contra la libreria de C completa. Y esto nos permite que nuestro driver haga cosas locas y complicadas si tener que implementar mucho.
• Podemos usar un debugger convensional
• Si se cuelga lo matamos y ya
• La memoria de usuario es swappeable (tenemos mas y puede ser bajada a disco para tener mas aun)
• Un driver bien diseniado puede permitir acceso concurrente a un dispositivo
• Ej: USB driver (libusb) y el x server (ambos conoces exactamente que es lo que hace y no hace el hardware)

Tiene sus desventajas:
• No hay interrupciones en el espacio de usuario
• Acceso directo a memoria es posible solamente con mmaping /dev/mem, y solo root puede.
• Para acceder a puertos I/O solo tenemos ioperm o iopl. (no todos los sistemas lo soporta) Acceder a /dev/port puede ser muy lento.
• Tiempo de respuesta meno, porque tiene qu ehabe run cambio de contexto cuando pasamos informacion entre el cliente y el hardware.
• !!! El driver puede ser bajado a disco (por swapping) !!! y ahi si que se pone lento todo. *se puede usar mlock, pero igual es inaceptable)
• Los dispositivos mas importantes no se pueden manejar en espacio de usuario (network interfaces y block devices)

El rol de un device driver…es proveer un mecanismo y no una politica.. Con esto empieza el libro Linux Device Driver 3. Ya que diferencia importante entre mecanismo y politica es una de las gandes ideas dentro del disenio de unix.
Mecanismo: que facilities(funcionalidades) son provistas para el usuario
Politica: como estas funcionalidades pueden ser usadas. Si estos dos temas estan bien entendidos y
abordados por diferentes secciones seccioes del programa o por programas diferentes obtenemos
un paquete de soft mucho mas facil de adaptar a las necesidades de cada usuario.

Cuando escribimos drivers debemos prestar atencion a lo siguiente:
tenemos que escribir codigo de kernel que acceda al hardware, pero no forzar ninguna politica
de acceso en particular, ya que distintos usuarios pueden llegar a tener distintas necesidades.
El driver tiene el solo objetivo de permitir el acceso de un usuario (o varios al mismo tiempo) al dispositivo y dejar a las aplicaciones que se encarguen de como usar el hardware.
Entonces el driver es flexible ofreciendo acceso al hardware sin poner restricciones.

Los drivers sin politicas tienen las siguientes caracteristicas comunes:
Proveen operaciones asincronas y sincronas.
Tiene la habilidad de poderse abrir multiples veces concurrentemente
Posee la habilidad de explotar todas las funcionalidades provistas por el hardware
y por lo general la falta de capas de software que simplifican las cosas
(son siempre las que proveen operaciones relacionadas con politicas)

Separando el kernel:
En todos los sitemas unix tenemos muchos procesos concurrentes que realizan diferentes tareas.
Estas se dividen en:
Process Management: El kernel esta a cargo de crear y destruir procesos y administrar su conexion con el mundo exterior. La comunicacion entre diferentes procesos (through signals, pipes, or interprocess communication primitives) es la funcionalidad basica que debe brindar el kernel.
• Memory Management
• FileSystems
• Device controls -> Device Drivers
• Networking

Vista del Kernel

Modulos pluggeables:
Linux posee la habilidad de extender sus funcionalidades en tiempo de ejecucion. Cada
set de funcionalidades se llama modulo.

Clases de dispositivos y Modulos:
Para linux hay 3 tipos de dispositivos (que tienen asociados sus respectivos tipos de modulos):
Char Module: stream de bytes (Ej: File) donde tenemos que implementar las operaciones comunes(syscalls) como read, write, open, close, etc. La unica diferencia entre un char device y un archivo es que en un archivo podemos movernos hacia adelante y hacia atras, y en los char devices debemos tratarlos como canales de datos donde solo podemos acceder secuencialmente.
Block Module: son dispositivos (como un disco duro) que pueden contener (hostear) un filesystem. En los sistemas unix un dispositivo de bloque solo puede manejar operaciones de I/O que transfieren uno o mas bloques (que usualmente son 512 bytes). Linux por su parte permite que tratemos a los block devices como char devices(nos permite hacer lecturas y escrituras). Por lo tanto en linux un dispositivo de bloque difiere de un dispositivo de tipo char en la manera en la que los datos son manejados a nivel de kernel.
Networking Module: encargados de transmicion y recepcion de paquetes. Aca tenemos funciones como send y recieve. No se conoce el concepto de conexion.. sino solo de envio y recepcion de paquetes. Al no ser stream oriented, no esta mapeado a un nodo en el filesystem. En unix la manera de acceder a estos dispositivos es mediante un nombre unico (eth0). Y la manera en la que se comunica el kernel con estos dispositivos es muy distinta que en los char y block devices.

JSR 317 = JPA 2.0

Febrero 22, 2008

En el caso de JPA nuevas funcionalidades seran tratadas por el grupo de expertos con el fin de refinar y flexibilizar la api de persistencia. Los temas que se tocaran en la especificacion son los siguientes:

Aspects that should be considered by the Expert Group for inclusion in this work include, but are not limited to, the following:

  • Expanded object/relational mapping functionality, including greater flexibility in combining existing mapping options, support for collections of embedded objects, multiple levels of embedded objects, ordered lists, combinations of access types, etc.
  • Additions to the Java Persistence query language
  • An API for “criteria” queries
  • Standardization of sets of “hints” for query configuration and for entity manager configuration
  • Standardization of additional metadata to support DDL generation and “Java2DB” mapping
  • Expanded pluggability contracts to support efficient passivation and replication of extended persistence contexts in Java EE environments
  • Standardization of additional contracts for entity detachment and merge, and persistence context management
  • Support for validation

Por el lado del calendario, es igual al de EJB 3.1.

En este caso la especificacion se basa en tomar las distintas features provistas por los distintos proveedores, tal es el caso de Toplink extensions para la mejora de JPQL y los criterion de Hibernate para la busqueda segun criterios.

JSR 318 = EJB 3.1

Febrero 22, 2008

La nueva especificacion de Enterprise Java Beans se esta gestando mediante la Java Specification Resource 318
La nueva version incluira cosas interesantes:

Aspects that should be considered by the Expert Group for inclusion in this work include, but are not limited to, the following:

  • Removal of the requirement for a separate local business interface.
  • Support for direct use of EJBs in the servlet container, including simplified packaging options.
  • Singleton beans.
  • Support for asynchronous session bean invocation.
  • Support for stateful web services via stateful session bean web service endpoints.
  • Specification of concurrency options for stateful session beans.
  • Application-level callback notifications, including for container initialization and shutdown.
  • EJB Timer Service enhancements to support cron-like scheduling, deployment-time timer creation, and stateful session bean timed objects.
  • An ejb-jar level component environment to simplify the specification of shared dependencies among components.

Como se puede ver, en este caso dejaron JPA 2.0 en una especificacion aparte (JSR 317), la cual promete bastantes mejoras y nuevas features.

Y el calendario estimado es el siguiente:

August 2007 Expert group formed
December 2007 Early Draft Review
April 2008 Public Review
Q4 2008 Final release.

Lamentablemente el Early Draft previsto para el mes de Diciembre pasado todavia no esta disponible.

Sin embargo ya hay varios blogs y varias paginas dedicadas a mostrar los avances y las nuevas features que EJB 3.1 presentara.

Aca les dejo algunos links como para que vayan viendo que se viene:

http://www.theserverside.com/tt/articles/article.tss?l=NewFeaturesinEJB3-1

Blood Inside – Ulver

Febrero 20, 2008

Luego de 3 anios de haber salido, este disco no cansa. Los noruegos saben como ir por el camino del Avant Garde.

Lo nuevo de Omar Rodriguez Lopez que sin duda hay que escuchar !

http://www.svetlian.com/Webmaster/art_diez.htm

En el vinculo anterior vemos un articulo que nos cuenta como hacer una pagina realmente anti usuario. Muy a tener en cuenta a la hora de hacer una web.

The Bedlam in Goliath

Febrero 20, 2008