static
void
globus_l_xio_win32_socket_complete(
    globus_i_xio_system_op_info_t *     op_info,
    globus_bool_t                       win32_thread)
{
    SOCKET                              fd;
    globus_result_t                     result;
    GlobusXIOName(globus_l_xio_win32_socket_complete);

    fd = op_info->handle->socket;
    
    GlobusXIOSystemDebugEnterFD(fd);
    
    if(!op_info->op)
    {
        /* internal usage */
        globus_l_xio_win32_socket_kickout(op_info);
        result = GLOBUS_SUCCESS;
    }
    else if(win32_thread)
    {
        result = globus_i_xio_win32_complete(
            globus_l_xio_win32_socket_kickout, op_info);
    }
    else
    {
        result = globus_callback_register_oneshot(
            0, 0, globus_l_xio_win32_socket_kickout, op_info);
    }
    /* really cant do anything else */
    if(result != GLOBUS_SUCCESS)
    {
        globus_panic(
            GLOBUS_XIO_SYSTEM_MODULE,
            result,
            _XIOSL("[%s:%d] Couldn't register callback"),
            _xio_name,
            __LINE__);
    }
    
    GlobusXIOSystemDebugExitFD(fd);
}
static
void
globus_l_xio_win32_socket_cancel_cb(
    globus_xio_operation_t              op,
    void *                              user_arg,
    globus_xio_error_type_t             reason)
{
    globus_i_xio_system_op_info_t *     op_info;
    GlobusXIOName(globus_l_xio_win32_socket_cancel_cb);

    GlobusXIOSystemDebugEnter();

    op_info = (globus_i_xio_system_op_info_t *) user_arg;
    
    /* this access of the handle is not safe if users destroy it
     * with outstanding callbacks.  I don't think that is allowed, so we
     * should be ok.
     */
    win32_mutex_lock(&op_info->handle->lock);
    {
        if(op_info->state != GLOBUS_I_XIO_SYSTEM_OP_COMPLETE && 
            op_info->state != GLOBUS_I_XIO_SYSTEM_OP_CANCELED)
        {
            op_info->error = reason == GLOBUS_XIO_ERROR_TIMEOUT
                ? GlobusXIOErrorObjTimeout()
                : GlobusXIOErrorObjCanceled();
            
            if(op_info->state == GLOBUS_I_XIO_SYSTEM_OP_NEW)
            {
                op_info->state = GLOBUS_I_XIO_SYSTEM_OP_CANCELED;
                    
                GlobusXIOSystemDebugPrintf(
                    GLOBUS_I_XIO_SYSTEM_DEBUG_INFO,
                    ("[%s] fd=%lu, Canceling NEW\n",
                        _xio_name, (unsigned long)op_info->handle->socket));
            }
            else
            {
                globus_result_t         result;

                op_info->state = GLOBUS_I_XIO_SYSTEM_OP_COMPLETE;
                
                GlobusXIOSystemDebugPrintf(
                    GLOBUS_I_XIO_SYSTEM_DEBUG_INFO,
                    ("[%s] fd=%lu, Canceling Pending\n",
                        _xio_name, (unsigned long)op_info->handle->socket));
                
                if(op_info->handle->read_info == op_info)
                {
                    op_info->handle->read_info = 0;
                }
                else
                {
                    globus_assert(op_info->handle->write_info == op_info);
                    op_info->handle->write_info = 0;
                }
                
                /* unregister and kickout now */
                result = globus_callback_register_oneshot(
                    0,
                    0,
                    globus_l_xio_win32_socket_kickout,
                    op_info);
                /* really cant do anything else */
                if(result != GLOBUS_SUCCESS)
                {
                    globus_panic(
                        GLOBUS_XIO_SYSTEM_MODULE,
                        result,
                        _XIOSL("[%s:%d] Couldn't register callback"),
                        _xio_name,
                        __LINE__);
                }
            }
        }
    }
    win32_mutex_unlock(&op_info->handle->lock);

    GlobusXIOSystemDebugExit();
}
globus_result_t
globus_xio_stack_push_driver(
    globus_xio_stack_t                  stack,
    globus_xio_driver_t                 driver)
{
    globus_xio_driver_t                 p_d;
    globus_i_xio_stack_t *              xio_stack;
    globus_result_t                     res = GLOBUS_SUCCESS;
    GlobusXIOName(globus_xio_stack_push_driver);

    GlobusXIODebugEnter();
    
    if(stack == NULL)
    {
        res = GlobusXIOErrorParameter("stack");
        goto err;
    }
    if(driver == NULL)
    {
        res = GlobusXIOErrorParameter("driver");
        goto err;
    }

    xio_stack = (globus_i_xio_stack_t *) stack;

    /* if in the transport position and has a push stack */
    if(driver->push_driver_func != NULL && xio_stack->pushing_driver != driver)
    {
        p_d = xio_stack->pushing_driver;
        xio_stack->pushing_driver = driver;
        res = driver->push_driver_func(driver, xio_stack);
        xio_stack->pushing_driver = p_d;
        if(res != GLOBUS_SUCCESS)
        {
            goto err;
        }
    }
    /* if a transport driver position */
    else if(xio_stack->size == 0)
    {
        if(driver->transport_open_func == NULL)
        {
            res = GlobusXIOErrorInvalidDriver(
                _XIOSL("open function not defined"));
            goto err;
        }
        else
        {
            xio_stack->size++;
            globus_list_insert(&xio_stack->driver_stack, driver);
        }
    }
    else if(driver->transport_open_func != NULL)
    {
        res = GlobusXIOErrorInvalidDriver(
            _XIOSL("transport can only be at bottom of stack"));
        goto err;
    }
    else
    {
        xio_stack->size++;
        globus_list_insert(&xio_stack->driver_stack, driver);
    }

    GlobusXIODebugExit();
    return GLOBUS_SUCCESS;

  err:

    GlobusXIODebugExitWithError();
    return res;
}
globus_result_t
globus_xio_data_descriptor_init( 
    globus_xio_data_descriptor_t *      data_desc,
    globus_xio_handle_t                 handle)
{
    globus_result_t                     res = GLOBUS_SUCCESS;
    globus_i_xio_op_t *                 op;
    globus_i_xio_context_t *            context;
    GlobusXIOName(globus_xio_data_descriptor_init);

    GlobusXIODebugEnter();
    
    if(data_desc == NULL)
    {
        res = GlobusXIOErrorParameter("data_desc");
        goto err_parm;
    }
    if(handle == NULL)
    {
        res = GlobusXIOErrorParameter("handle");
        goto err;
    }

    context = handle->context;
    globus_mutex_lock(&context->mutex);
    {
        GlobusXIOOperationCreate(op, context);
        if(op != NULL)
        {
            op->type = GLOBUS_XIO_OPERATION_TYPE_DD;
            handle->ref++;
            GlobusXIODebugPrintf(
                    GLOBUS_XIO_DEBUG_INFO_VERBOSE,
                    (_XIOSL("[globus_xio_data_descriptor_init] :: handle ref at %d.\n"), handle->ref));

            op->_op_handle = handle;
            op->ref = 1;
            op->is_user_dd = GLOBUS_TRUE;
        }
        else
        {
            res = GlobusXIOErrorMemory("xio_dd");
        }
    }
    globus_mutex_unlock(&context->mutex);

    if(res != GLOBUS_SUCCESS)
    {
        goto err;
    }
    *data_desc = op;
    
    globus_mutex_lock(&globus_i_xio_mutex);
    {
        globus_list_insert(&globus_i_xio_outstanding_dds_list, op);
    }
    globus_mutex_unlock(&globus_i_xio_mutex);
    
    GlobusXIODebugExit();
    return GLOBUS_SUCCESS;

  err:
    *data_desc = NULL;
  err_parm:
    GlobusXIODebugExitWithError();
    return res;
}
globus_result_t
globus_xio_attr_destroy(
    globus_xio_attr_t                   attr)
{
    int                                 ctr;
    globus_result_t                     res = GLOBUS_SUCCESS;
    globus_result_t                     tmp_res;
    GlobusXIOName(globus_xio_attr_destroy);

    GlobusXIODebugEnter();
    
    if(attr == NULL)
    {
        res = GlobusXIOErrorParameter("attr");
        goto err;
    }
    
    globus_mutex_lock(&globus_i_xio_mutex);
    {
        if(!attr->unloaded)
        {
            for(ctr = 0; ctr < attr->ndx; ctr++)
            {
                GlobusXIODebugPrintf(
                    GLOBUS_XIO_DEBUG_INFO_VERBOSE, 
                    (_XIOSL("[globus_xio_attr_destroy]: destroying attr @0x%x "
                        "driver @0x%x, %s\n"), 
                    attr,
                    attr->entry[ctr].driver,
                    attr->entry[ctr].driver->name));
                                
                /* report the last seen error but be sure to attempt to clean 
                    them all */
                tmp_res = attr->entry[ctr].driver->attr_destroy_func(
                        attr->entry[ctr].driver_data);
                if(tmp_res != GLOBUS_SUCCESS)
                {
                    res = tmp_res;
                }
            }
            
            globus_list_remove(
                &globus_i_xio_outstanding_attrs_list,
                globus_list_search(
                    globus_i_xio_outstanding_attrs_list, attr));
        }
    }
    globus_mutex_unlock(&globus_i_xio_mutex);

    if(attr->user_open_sbj)
    {
        globus_free(attr->user_open_sbj);
    }
    if(attr->user_open_username)
    {
        globus_free(attr->user_open_username);
    }
    if(attr->user_open_pw)
    {
        globus_free(attr->user_open_pw);
    }
 
    globus_callback_space_destroy(attr->space);
    globus_free(attr->entry);
    globus_free(attr);
    if(res != GLOBUS_SUCCESS)
    {
        goto err;
    }

    GlobusXIODebugExit();
    return GLOBUS_SUCCESS;

  err:

    GlobusXIODebugExitWithError();
    return res;
}
static
void
globus_l_popen_waitpid(
    xio_l_popen_handle_t *              handle,
    int                                 opts)
{
    globus_result_t                     result = GLOBUS_SUCCESS;
    int                                 status;
    int                                 rc;
    globus_reltime_t                    delay;
    GlobusXIOName(globus_l_popen_waitpid);

#ifdef WIN32
    result = GlobusXIOErrorSystemResource("not available for windows");
#else
    rc = waitpid(handle->pid, &status, opts);
    if(rc > 0)
    {
        /* if program exited normally, but with a nonzero code OR
         * program exited by signal, and we didn't signal it */
        if(((WIFEXITED(status) && WEXITSTATUS(status) != 0) || 
            (WIFSIGNALED(status) && handle->kill_state != GLOBUS_L_XIO_POPEN_NONE))
            && !handle->ignore_program_errors)
        {
            /* read programs stderr and dump it to an error result */
            globus_size_t                   nbytes = 0;
            globus_xio_iovec_t              iovec;
            char                            buf[8192];

            iovec.iov_base = buf;
            iovec.iov_len = sizeof(buf) - 1;
            
            result = globus_xio_system_file_read(
                handle->err_system, 0, &iovec, 1, 0, &nbytes);
            
            buf[nbytes] = 0;

            if(WIFEXITED(status))
            {
                result = globus_error_put(
                    globus_error_construct_error(
                        GLOBUS_XIO_MODULE,
                        GLOBUS_NULL,
                        GLOBUS_XIO_ERROR_SYSTEM_ERROR,
                        __FILE__,
                        _xio_name,
                        __LINE__,
                        _XIOSL("popened program exited with an error "
                               "(exit code: %d):\n%s"),
                        WEXITSTATUS(status), 
                        buf));
            }
            else
            {
                result = globus_error_put(
                    globus_error_construct_error(
                        GLOBUS_XIO_MODULE,
                        GLOBUS_NULL,
                        GLOBUS_XIO_ERROR_SYSTEM_ERROR,
                        __FILE__,
                        _xio_name,
                        __LINE__,
                        _XIOSL("popened program was terminated by a signal"
                               "(sig: %d)"),
                        WTERMSIG(status)));
            }
        }

        globus_xio_system_file_close(handle->errfd);
        globus_xio_system_file_destroy(handle->err_system);

        globus_xio_driver_finished_close(handle->close_op, result);
        globus_l_xio_popen_handle_destroy(handle);
    }
    else if(rc < 0 || opts == 0)
    {
        /* If the errno is ECHILD, either some other thread or part of the
         * program called wait and got this pid's exit status, or sigaction
         * with SA_NOCLDWAIT prevented the process from becoming a zombie. Not
         * really an error case.
         */
        if (errno != ECHILD)
        {
            result = GlobusXIOErrorSystemError("waitpid", errno);
        }

        globus_xio_system_file_close(handle->errfd);
        globus_xio_system_file_destroy(handle->err_system);

        globus_xio_driver_finished_close(handle->close_op, result);
        globus_l_xio_popen_handle_destroy(handle);
    }
    else
    {
        
        handle->wait_count++;
        
        if(handle->canceled)
        {
            switch(handle->kill_state)
            {
                case GLOBUS_L_XIO_POPEN_NONE:
                    if(handle->wait_count > 5000 / GLOBUS_L_XIO_POPEN_WAITPID_DELAY)
                    {
                        handle->kill_state = GLOBUS_L_XIO_POPEN_TERM;
                        kill(handle->pid, SIGTERM);
                    }
                    break;
                case GLOBUS_L_XIO_POPEN_TERM:
                    if(handle->wait_count > 15000 / GLOBUS_L_XIO_POPEN_WAITPID_DELAY)
                    {
                        handle->kill_state = GLOBUS_L_XIO_POPEN_KILL;
                        kill(handle->pid, SIGKILL);
                    }
                    break;
                default:
                    break;
            } 
        }
        
        GlobusTimeReltimeSet(delay, 0, GLOBUS_L_XIO_POPEN_WAITPID_DELAY);
        globus_callback_register_oneshot(
            NULL,
            &delay,
            globus_l_xio_popen_close_oneshot,
            handle);         
    }

#endif
    GlobusXIOPOpenDebugExit();
}