aboutsummaryrefslogblamecommitdiffstats
path: root/erts/emulator/test/busy_port_SUITE_data/scheduling_drv.c
blob: 2008b33a721849f64879e20b9e3d290bbebf625e (plain) (tree)
1
2
3
4


                   
                                                        

























































































































































































                                                                                
/*
 * %CopyrightBegin%
 * 
 * Copyright Ericsson AB 2009-2013. All Rights Reserved.
 * 
 * The contents of this file are subject to the Erlang Public License,
 * Version 1.1, (the "License"); you may not use this file except in
 * compliance with the License. You should have received a copy of the
 * Erlang Public License along with this software. If not, it can be
 * retrieved online at http://www.erlang.org/.
 * 
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 * 
 * %CopyrightEnd%
 */

#ifdef __WIN32__
#include <windows.h>
#else
#include <sys/select.h>
#endif
#include <errno.h>
#include <stdio.h>
#include "erl_driver.h"

#define get_int32(s) ((((unsigned char*) (s))[0] << 24) | \
                      (((unsigned char*) (s))[1] << 16) | \
                      (((unsigned char*) (s))[2] << 8)  | \
                      (((unsigned char*) (s))[3]))

#define ERTS_TEST_SCHEDULING_DRV_NAME "scheduling_drv"
#define ERTS_TEST_SCHEDULING_DRV_FLAGS  \
  ERL_DRV_FLAG_USE_PORT_LOCKING | ERL_DRV_FLAG_SOFT_BUSY

ErlDrvData start(ErlDrvPort port, char *command);
void output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len);
ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf,
		     ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen);
void stop(ErlDrvData drv_data);
void timeout(ErlDrvData drv_data);

static void delay(unsigned ms);

static ErlDrvEntry busy_drv_entry = { 
    NULL /* init */,
    start,
    stop,
    output,
    NULL /* ready_input */,
    NULL /* ready_output */,
    ERTS_TEST_SCHEDULING_DRV_NAME,
    NULL /* finish */,
    NULL /* handle */,
    control,
    timeout,
    NULL /* outputv */,
    NULL /* ready_async */,
    NULL /* flush */,
    NULL /* call */,
    NULL /* event */,
    ERL_DRV_EXTENDED_MARKER,
    ERL_DRV_EXTENDED_MAJOR_VERSION,
    ERL_DRV_EXTENDED_MINOR_VERSION,
    ERTS_TEST_SCHEDULING_DRV_FLAGS,
    NULL /* handle2 */,
    NULL /* handle_monitor */,
    NULL /* stop_select */
};

#define DBG(data,FMT)
/* #define DBG(data,FMT) printf("0x%.8lx: %s",driver_caller(data->port),FMT); */

typedef struct SchedDrvData {
  ErlDrvPort port;
  char data[255];
  int curr;
  int use_auto_busy;
} SchedDrvData;

DRIVER_INIT(busy_drv)
{
    return &busy_drv_entry;
}

ErlDrvData start(ErlDrvPort port, char *command)
{
  SchedDrvData *d = driver_alloc(sizeof(SchedDrvData));
  d->port = port;
  d->curr = 0;
  d->use_auto_busy = 0;
  DBG(d,"start\r\n");
  return (ErlDrvData) d;
}

void stop(ErlDrvData drv_data) {
  SchedDrvData *d = (SchedDrvData*)drv_data;
  driver_output(d->port,d->data,d->curr);
  DBG(d,"close\r\n");
  driver_free(d);
  return;
}

void timeout(ErlDrvData drv_data) {
  SchedDrvData *d = (SchedDrvData*)drv_data;
  set_busy_port(d->port, 0);
  DBG(d,"timeout\r\n");
}

void output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len)
{
  int res;
  unsigned int command = *buf;
  SchedDrvData *d = (SchedDrvData*)drv_data;
  
  switch (command) {
  case 'B': /* busy */
    DBG(d,"busy: ");
    set_busy_port(d->port, 1);
    break;
  case 'L': /* busy long call */
    DBG(d,"long: ");
    delay(buf[5]*100);
    set_busy_port(d->port, 1);
    break;
  case 'D': /* delay call */
    DBG(d,"delay: ");
    delay(buf[5]*100);
    break;
  case 'N': /* not busy */
    DBG(d,"not");
    set_busy_port(d->port, 0);
    goto done;
  case 'C': /* change state */
    DBG(d,"chang: ");
    break;
  case 'G': /* get state */
    DBG(d,"get : ");
    driver_output(d->port,d->data,d->curr);
    return;
  default:
    driver_failure_posix((ErlDrvPort) drv_data, EINVAL);
    break;
  }
  if (len > 1) {
    unsigned int val = get_int32(buf+1);
    fprintf(stderr,"%u",val);
    d->data[d->curr++] = val;
  }
 done:
 fprintf(stderr,"\r\n");
}

ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf,
		     ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen)
{
    switch (command) {
    case 'B': /* busy */
	set_busy_port((ErlDrvPort) drv_data, 1);
	break;
    case 'N': /* not busy */
	set_busy_port((ErlDrvPort) drv_data, 0);
	break;
    default:
	driver_failure_posix((ErlDrvPort) drv_data, EINVAL);
	break;
    }
    return 0;
}


/*
 * Delays (sleeps) the given number of milli-seconds.
 */

static void delay(unsigned ms)
{
  fprintf(stderr,"delay(%u)",ms);
#ifdef __WIN32__
  Sleep(ms);
#else
  struct timeval t;
  t.tv_sec = ms/1000;
  t.tv_usec = (ms % 1000) * 1000;

  select(0, NULL, NULL, NULL, &t);
#endif
}