Creación de procesos con fork() en Linux I March 27th, 2009 by sxceron

Un proceso es la unidad b谩sica de ejecuci贸n de cualquier sistema operativo, y en la actualidad muchos de estos sistemas operativos hacen uso de multiprocesos, es decir, creaci贸n de varios procesos para la ejecuci贸n de una tarea espec铆fica.

En los sistemas operativos se tiene un 谩rbol de procesos debido a que cada vez que un proceso nuevo es creado (proceso hijo), este contiene la informaci贸n del que lo creo (proceso padre). De igual forma, los procesos hijo pueden crear subprocesos, convirti茅ndose estos primeros en procesos padre.

Funci贸n fork()

Sintaxis

pid_t fork(void);

Dependencias

#include <sys/types.h>
#include <unistd.h>

La funci贸n fork() regresa tres diferentes valores:

  • Menor a cero si la fallo la creaci贸n del proceso (<0)
  • Igual a cero cuando se ejecuta el c贸digo del hijo (proceso creado) (=0)
  • Mayor a cero si se ejecuta el c贸digo del padre (>0)

Por 煤ltimo, la ejecuci贸n de cada bloque de c贸digo en la bifurcaci贸n se realiza de manera diferente cada vez que se ejecuta el programa debido a que esta es determinada por el planificador de procesos de cada sistema opertivo.

Funci贸n wait()

Sintaxis

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);

Dependencias

#include <sys/types.h>
#include <sys/wait.h>

Descripci贸n

Wait es una llamada al sistema que a grandes rasgos detiene la ejecuci贸n de un proceso padre hasta que alguno de sus hijos termina. Este comportamiento puede cambiar seg煤n las opciones que le sean pasadas a esta funci贸n.

La funci贸n wait suspende la ejecuci贸n del proceso actual hasta que un proceso hijo ha terminado, o hasta que se produce una se帽al cuya acci贸n es terminar el proceso actual o llamar a la funci贸n manejadora de la se帽al. Si un hijo ha salido cuando se produce la llamada (lo que se entiende por proceso "zombie"), la funci贸n vuelve inmediatamente. Todos los recursos del sistema reservados por el hijo son liberados.

Creacion de arbol de procesos.

El siguiente programa crea un 谩rbol de procesos que muestra el id del padre si se esta ejecutando el c贸digo del hijo, o el id de los hijos en el caso de que sea un proceso padre el que se encuentra en ejecici贸n.

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
 
int main(char *argv[]) {
    int pid, pidi, pidj;
    int i, j, k, l;
    int sti, stj;
    int tprocess[3][2];
    int ttprocess[3];
    pid = fork();
    if (!pid) {
        for (i = 0; i < 3; i++) {
           pidi = fork();
            if (pidi == 0) {
                for (j = 0; j < 2; j++) {
                    pidj = fork();
                    if (pidj == 0) {
                        printf("Mi id es %d y el de mi padre es: %d\n", getpid(), getppid());
                        exit(0);
                    }
                    tprocess[i][j] = pidj;
                }
                if (pidj != 0) {
                    for (k = 0; k < 2; k++)
                        waitpid(tprocess[i][k], &stj, 0);
                    printf("Soy el padre: %d y mis hijos son:", getpid());
                    for (k = 0; k < 2; k++)
                        printf(" %d ", tprocess[i][k]);
                    printf("\n");
                    exit(0);
                }
            }
            ttprocess[i] = pidi;
        }
        if (pidi != 0) {
            for (l = 0; l < 3; l++)
                waitpid(ttprocess[l], &sti, 0);
            printf("Soy el padre: %d y mis hijos son:", getpid());
            for (l = 0; l < 3; l++)
                printf(" %d ", ttprocess[l]);
            printf("\n");
        }
    }
}

Para ejecutar el codigo solo es necesario ejecutar el siguiente comando:

gcc fork1.c -o fork1
./fork1

La salida deber ser algo asi:

NOTA: Las funciones getpid() y getppid() sirven para obtener el id del proceso en ejecuci贸n,
o el id del padre del proceso actual (en caso de que exista,
de lo contrario regresar谩 un numero negativo).

+ Manejo de cadenas en ensamblador (x86) I By sxceron March 25th, 2009 y hay 1 comentario

Ensamblador es un lenguaje de programacion de bajo nivel que permite comunicarnos con las interrupciones del procesador de manera casi directa.

Empezar a trabajar con ensamblador es un poco complicado al principio ya que al estar acostumbrados a C, Java, C#, el uso de nemonicos es desconocido para muchos.

Los nemonicos son palabras cortas reservadas de cada set de instrucciones de cada procesador que permiten ejecutar operaciones sobre el procesador y la memoria. Una de las funciones en el x86 mas usual es la de INT, ya que con esta llamamos a una interrupcion del equipo y pedimos un servicio.

Algunas de las interrupciones como la 21h contienen dentro muchas funciones que permiten acceder a diferentes servicios.

En este post voy a hacer uso de esta interrupcion y algunas de sus funciones para manipular cadenas de caracteres (que en teoria, son cadenas de cualquier cosa) y mostrar algunos ejemplos clasicos de aplicacion.

Como les habia mencionado antes, la interrupcion 21h tiene dentro varias funciones que se deben establecer en el registro AH (AX en su parte alta) de donde el procesador leera que servicio se invocara.

Ahora veamos algunos ejemplos basicos de asm con cadenas.

Copiar una cadena a otra

.model small
 
.code
 
inicio:
 
; Direccion del segmento de datos en ds, es
mov ax, @data
mov ds, ax
mov es, ax
 
; Leer de izq a derecha
cld
 
; Asigna las cadenas a copiar
mov cl,20   ; Longitud
lea si,cad1 ; Origen
lea di,cad2 ; Destino
rep movsb   ; Mueve la cadena
 
; Imprime cad1
lea dx,cad1
mov ah,9h ; Funcion 9H de la interrupcion 21h para imprimir una cadena en pantalla
int 21h   ; La cadena debe estar en dx
 
; Imprime cad2
lea dx,cad2
mov ah,9h ; Funcion 9H de la interrupcion 21h para imprimir una cadena en pantalla
int 21h   ; La cadena debe estar en dx
 
; Termina el programa
mov ah,4ch ; Funcion 4CH de la int 21H para finalizar el programa con codigo de retorno
int 21h    ; El codigo es opcional y va en AL
 
.data
cad1 db 10,13,"Esta es la cadena1", "$"
cad2 db 20 dup (' '), "$"
 
.stack
 
end inicio

Nota: .model small especifica el modelo de memoria, especificado por las siguientes opciones.

  • TINY: El codigo y los datos estan en el mismo segmento de maximo 64k.
  • SMALL: El codigo y los datos estan en diferentes segmentos, pero estos no superan los 64k
    Es usado en la mayoria de elas aplicaciones
  • MEDIUM: El codigo puede sobrepasar los 64k, pero el segmento de datos no.
  • COMPACT: El codigo es menor a 64k, pero el segmento de datos puede ser mayor.
  • LARGE: En este caso, tanto el segmento de datos como el de codigo pueden sobrepasar los 64k.
  • HUGE: Igual que LARGE, pero los arreglos declarados tambien pueden ser mayores a 64k.

+ Sistema básico de Cache con AspecJ + Anotaciones By sxceron February 21st, 2009 y hay 0 comentarios

Una de las ventajas de usar aspectos sobre un proyecto, es que podemos agregar modulos de funcionalidad sin tener que tocar una sola linea de c贸digo de nuestra aplicaci贸n.

En este tutorial veremos como implementar un sistema b谩sico de caching usando aspectj con anotaciones. Las anotaciones nos servir谩n para especificar que bloques de c贸digo o que funciones ser谩n guardadas en cache.

Primero que nada necesitamos crear una nueva anotaci贸n que identifique que m茅todos van a ser cacheados por el aspecto. La anotaci贸n quedar铆a de la siguiente forma:

Cachable.java

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) 
public @interface Cachable { 
}

Ahora vamos a crar nuestro aspecto y dentro de el un Advice(Around). Around por si no lo saben, es ejecutado como su nombre lo dice, alrededor del m茅todo, y permite detener la ejecuci贸n de este y regresar un valor 贸 continuar normalmente.

CacheAspect.java

import java.util.HashMap;
import java.util.Map; 
import org.aspectj.lang.ProceedingJoinPoint; 
import org.aspectj.lang.annotation.Around; 
import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Pointcut; 
import annotations.Cachable; 
 
@Aspect 
public class CacheAspect { 
 
    final static int TIME_CACHE = 300; 
    private final Map<String, CacheJoinPoint> cache = new WeakHashMap<String, CacheJoinPoint>(); 
 
    @Around("execution(* *(..)) && @annotation(annotations.Cachable)") 
    public Object aroundProfileMethods(final ProceedingJoinPoint thisJoinPoint) 
		throws Throwable { 
        final String thisJoinPointName = AspectJHelper.getJoinPointName(thisJoinPoint); 
        final String thisJoinPointArgs = AspectJHelper.getJointPointArgs(thisJoinPoint); 
        final String objName = thisJoinPointName + "-" + thisJoinPointArgs; 
        CacheJoinPoint obj = this.cache.get(objName); 
        if (obj == null) { 
            Object value = thisJoinPoint.proceed(); 
            CacheJoinPoint cjp = new CacheJoinPoint(System.currentTimeMillis(), value); 
            this.cache.put(objName, cjp); 
            return value; 
        }else{ 
            if(System.currentTimeMillis() - obj.getTime() > TIME_CACHE){ 
                Object value = thisJoinPoint.proceed(); 
                CacheJoinPoint cjp = new CacheJoinPoint(System.currentTimeMillis(), value); 
                this.cache.put(objName, cjp); 
                return value; 
            } 
        } 
        return obj.getValue(); 
    } 
}

El aspecto es muy sencillo, la constante TIME_CACHE determinar谩 cuanto tiempo durar谩 nuestro objeto en cache en milisegundos. El HashMap es un pequeño contenedor de objetos y ser谩 usado para guardar los valores regresados por los m茅todos ya ejecutados.

WeakHashMap. Esta clase implementa java.util.Map, pero las keys se almacenan como objetos con referencias d茅biles. Con esto se dejar谩 la responsabilidad de vaciar la cach茅 al recolector de basura.

La clase CacheJoinPoint nos servir谩 como referencia para guardar tanto el valor regresado por el m茅todo ejecutado, como la hora a la que fue ejecutado para determinar despues si este ya excedio su tiempo de vida y tendr铆a que ser ejecutado nuevamente, de lo contrario es obtenido del cache.

CacheJoinPoint.java

public class CacheJoinPoint { 
    private Object value; 
    private long time; 
 
    public CacheJoinPoint(long time, Object value){ 
        this.time = time; 
        this.value = value; 
    } 
 
    public long getTime() { 
        return time; 
    } 
 
    public void setTime(long time) { 
        this.time = time; 
    } 
 
    public Object getValue() { 
        return value; 
    } 
 
    public void setValue(Object value) { 
        this.value = value; 
    } 
}

La clase AspectJHelper nos sirve como auxiliar para regresar un nombre 煤nico a cada m茅todo ejecutado y sus argumentos (en caso de que existan).

AspectJHelper.java

import org.aspectj.lang.JoinPoint; 
 
public class AspectJHelper { 
 
    public static final String getJoinPointName(final JoinPoint joinPoint) { 
        return joinPoint.getThis().getClass().getSimpleName() + 
		"." + joinPoint.getSignature().getName(); 
    } 
 
    public static final String getJointPointArgs(final JoinPoint joinPoint) { 
        final StringBuilder buf = new StringBuilder(); 
        for (final Object arg : joinPoint.getArgs()) { 
            buf.append(arg.getClass().getSimpleName() + "-" + arg + "+"); 
        } 
        return buf.toString().replaceAll("\\+$", ""); 
    } 
}

Por 煤ltimo, para hacer uso de la cache solo es necesario poner una anotacion sobre el metodo que vayamos a querer guardar en la cache, de esta forma:

@Cachable
public Objeto getObjeto(int param) {
	...
	return value;
}

+ Introduccion a XStream parte 1 By sxceron January 15th, 2009 y hay 1 comentario

Existen muchas librerias de  java que permiten el manejo de xml(DOM4J, XPath, SAX, etc), pero no todas ellas nos permiten mapear o convertir facilmente de XML a POJOs y viceversa.

XStream es una libreria que tiene muchas opciones a la hora de converitir nuestro xml a una clase de java (conversores, persistencia, json, alias, anotaciones, etc). XStream hace uso de la API Reflection de java para hacer el mapeo del xml, asi que nuestras clases tendran que llevar los campos con sus respectivos set/get.

Para hace uso de esta libreria, prmero hay que bajarnos la distribucion binaria de la pagina http://xstream.codehaus.org/download.html

Agregar los archivos en el classpath ó en las librerias de nuestro proyecto NetBeans.

image

El archivo xstream-[version].jar  es el nucleo de la API y XPP3 es una implementacion mas veloz que el estandar JAXP para el parseo de XML.

Ahora vamos a hacer nuestro primer ejemplo de serializacion con XStream.

Para empezar necesitamos crear un POJO (Un simple archivo java que contiene propiedades y sus respectivos set & get).

Persona.java

public class Persona {
    private String nombre;
    private int edad;
    private List<String> amigos = new ArrayList<String>();
 
    public String getNombre() {
        return nombre;
    }
 
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
 
    public int getEdad() {
        return edad;
    }
 
    public void setEdad(int edad) {
        this.edad = edad;
    }
 
    public List<String> getAmigos() {
        return amigos;
    }
 
    public void addAmigo(String amigo) {
        amigos.add(amigo);
    }
}

Despues de eso vamos a crear una aplicacion java, en este caso una con main para hacer uso de la libreria.

XStreamTest.java

import com.thoughtworks.xstream.XStream;
 
public class XStreamTest { 
 
    public static void main(String[] args) {
        XStream xstream = new XStream();
        xstream.alias("persona", Persona.class);
        Persona yo = new Persona();
        yo.setNombre("Sergio Ceron");
        yo.setEdad(19);
        yo.addAmigo("Some friend ;)");
        String xml = xstream.toXML(yo);
        System.out.println(xml);
    }
 
}

Al ejecutar este ejemplo veremos algo asi:

<persona> 
  <nombre>Sergio Ceron</nombre> 
  <edad>19</edad> 
  <amigos> 
    <string>Some friend ;)</string> 
  </amigos> 
</persona>

Para que vean que hace la sentencia xstream.alias, la pueden quitar y el xml se generará sin ningun error pero de la siguiente forma:

<xstreamsample.persona> 
  <nombre>Sergio Ceron</nombre> 
  <edad>19</edad> 
  <amigos> 
    <string>Some friend ;)</string> 
  </amigos> 
</xstreamsample.persona>

Donde xstreamsample es el paquete donde esta la clase Persona. Es decir, cambia el nombre completo de la clase por el alias que especifiquemos para que nuestro xml se vea mejor.

Por otra parte, para regresar el xml a una clase java, es tan sencillo como lo siguiente.

public static void main(String[] args) {
        XStream xstream = new XStream();
        xstream.alias("persona", Persona.class);
 
        String xml =
                "<persona>" +
                "   <nombre>Sergio Ceron</nombre>" +
                "   <edad>19</edad>" +
                "   <amigos>" +
                "       <string>Some friend ;)</string>" +
                "   </amigos>" +
                "</persona>";
        Persona yo = (Persona)xstream.fromXML(xml);
        System.out.println( "Me llamo: " + yo.getNombre() );
        System.out.println( "Tengo: " + yo.getEdad() + " a帽os" );
        System.out.println( "Mis amigos: " );
        for( String amigo : yo.getAmigos() )
            System.out.println( amigo );
    }

Y el resultado es:


Me llamo: Sergio Ceron

Tengo: 19 años

Mis amigos:

Some friend ;)

Como ven, es muy sencillo serializar con xstream. Despues veremos algunas funciones mas complejas de esta libreria como conversores y el uso de anotaciones para simplificar codigo.

+ NetBeans + IceFaces + Hibernate + Anotaciones By sxceron January 14th, 2009 y hay 0 comentarios

Un video tutorial que implementa estas tecnologias sobre el IDE NetBeans.

Sin mas que decir aqui esta el video y en mayor calidad http://www.youtube.com/watch?v=G6Bf2VCedBs haciendo click debajo del video y "ver con alta calidad".

Para descargar el proyecto haz click aqui, y lo unico que tienen que hacer es abrir el projecto y crear la base de datos del video.

Una vez creada sobre derby o mysql (como quieras), modifica el archivo hibernate.cfg.xml que esta en el paquete por defecto y el archivo persistence.xml que esta en los archivos de configuración.

+ Spring + Hibernate + Acegi ( Custom UserDetailsService ) By sxceron January 13th, 2009 y hay 0 comentarios

En este tutorial quiero mostrar como implementar un UserDetailsService personalizado que nos permita recueperar el usuario que ha iniciado sesion en acegi cargando el objeto en la sesión de Hibernate.

Bueno, la verdad no pondre el tutorial completo desde cero, espero que esto les sirva de ayuda pero la parte de la implementacion de acegi + hibernate + spring la dejare para otro tutorial, el truco aqui es que hay cosas que no estan bien documentadas y esta es una de ellas.

La parte que hay que agregar/modificar en el applicationContext.xml de spring es la siguiente:

<bean id="daoAuthenticationProvider" 
	class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
        <property name="userDetailsService">
		<ref bean="userDetailsService" />
        </property>
        <property name="passwordEncoder">
		<ref local="passwordEncoder"/>
	</property>
    </bean>
 
    <!-- Custom User Detail Service -->
    <bean id="userDetailsService" 
	class="org.security.AuthenticationJdbcDaoImpl">
        <property name="dataSource">
            <ref bean="dataSource"/>
        </property>
        <property name="userInfoObjectTypes">
            <list>
                <value>Usuario</value>
            </list>
        </property>
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

Donde:

  • userDetailsService: Es el bean que obtendra el usuario que ha iniciado sesi贸n y lo dara de alta en la sesion de Hibernate
  • org.security.AuthenticationJdbcDaoImpl: Es la clase donde estara la autenticacion personalizada
  • userInfoObjectTypes: Es una dependencia que inyectaremos para decirle de que tabla debera obtener el usuario que haya iniciado sesion, pongo una lista en caso de que sean mas de una tabla donde este nuestro usuario usando herencias o algo asi.
  • dataSource: Es el bean que deberiamos ya tener y que apunta a el orgien de datos del sistema de persistencia que estemos usando
  • sessionFactory: Es el session factory de Hibernate

Y bueno de aqui nos vamos a la clase AuthenticationJdbcDaoImpl.

import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.acegisecurity.userdetails.jdbc.JdbcDaoImpl;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessException;
 
public class AuthenticationJdbcDaoImpl extends JdbcDaoImpl {
 
    private String[] userInfoObjectTypes;
    private SessionFactory sessionFactory;
 
    @Override
    protected void initMappingSqlQueries() {
        super.setUsersByUsernameQuery("select nombre as username, password, enabled"
		+" from usuario where nombre = ?");
        super.setAuthoritiesByUsernameQuery("select usuario.nombre as username, "
		+"authorities.permission as authority from usuario, authorities, "
		+"usuario_authorities where usuario_id=usuario.id and "
		+"autorities_id=authorities.id and usuario.nombre = ?");
        super.initMappingSqlQueries();
    }
 
    @Override
    public UserDetails loadUserByUsername(String username) {
        try {
            UserDetails user = super.loadUserByUsername(username);
            Session session = sessionFactory.openSession();
            for (int i = 0; i < userInfoObjectTypes.length; i++) {
 
                Object userInfo = session.createQuery("from " + userInfoObjectTypes[i] + 
			" where nombre = '" + username + "'").uniqueResult();
                if (userInfo != null) {
                    session.close();
                    return new CustomUser(user.getUsername(), user.getPassword(), 
			user.isEnabled(), user.getAuthorities(), userInfo);
                }
            }
            session.close();
            return new CustomUser(user.getUsername(), user.getPassword(), 
			user.isEnabled(), user.getAuthorities());
        } catch (UsernameNotFoundException ex1) {
            ex1.printStackTrace();
            throw ex1;
        } catch (DataAccessException ex2) {
            ex2.printStackTrace();
            throw ex2;
        }
    }
 
    public void setUserInfoObjectTypes(String[] userInfoObjectTypes) {
        this.userInfoObjectTypes = userInfoObjectTypes;
    }
 
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
}

La clase CustomUser

import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.userdetails.User;
 
public class CustomUser extends User {
 
    private Object userInfo;
 
    public CustomUser(String username, String password, boolean isEnabled, 
			GrantedAuthority[] authorities, Object user) {
        super(username, password, isEnabled, true, true, true, authorities);
        this.setUserInfo(user);
    }
 
    public CustomUser(String username, String password, boolean isEnabled, 
			GrantedAuthority[] arrayAuths) {
        super(username, password, isEnabled, true, true, true, arrayAuths);
    }
 
    public Object getUserInfo() {
        return userInfo;
    }
 
    public void setUserInfo(Object userInfo) {
        this.userInfo = userInfo;
    }
}

Como se daran cuenta, el userInfo es el que tendra nuestro usuario logueado, pero como tambien veran este esta siendo cargado desde una sesion nueva y esto causa muchos problemas a la hora de tener colecciones en nuestros entity beans, asi que lo que hartemos sera reasociarlo con la otra sesion una vez que se haya autenticado.

Esta vez lo hare con icefaces y desde un controlador de spring.

@Resource
private Dao dao;
...
public String auth_login_action(){
        try{
            authenticate( j_username.getText(), j_password.getValue().toString() );
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
            CustomUser customUser = (CustomUser)(auth.getPrincipal());
            for( GrantedAuthority ga : customUser.getAuthorities() )
                System.out.println( ga.getAuthority() );
            Object usuario =  customUser.getUserInfo();
            dao.lock(usuario);
            if( usuario instanceof Empleado ){
                empleadoMgr.setEmpleado((Empleado)usuario);
            }
            return "sucess";
        }catch(Exception e){}
        return null;
    }
...

Aqui @Resource es una anotacion de java para inyectar el Dao que esta con hibernate, eso depende de cada quien tener el suyo( Si no saben como crearlo despues subire otro tutorial para eso ).

La parte importante es la de dao.lock que si no usan un Dao, podria ser:

session.lock(usuario, LockType.NONE)

getHibernateTemplate().lock(usuario, LockType.NONE)

Y es la que se encarga de reasociar el objeto de una sesi贸n a otra dentro del contexto de Hibernate.

Despu茅s de todo esto las colecciones no se cargaran a menos que tengamos un FetchType EAGER con anotaciones o si fijamos lazy=”false” y dejamos fetch por defecto (fetch=”select”), implica que cuando se recuperen los datos de TA también se recuperan los de TB, pero se hará con 1+n consultas a la base de datos.

Otra forma de cargar una coleccion que es mas eficiente es por ejemplo:

Hibernate.initialize(empresa.getEmpleados());

Esta ultima sentencia forza a cargar una coleccion de un entity bean.

Por ahora eso seria todo, si tienen dudas o partes de esto que no entiendan me pueden enviar un correo a ceronxero (arroba) hotmail (punto) com y tratare de responder lo mas rapido en la medida de lo posible.

Saludos.