globus_result_t
globus_i_xio_win32_complete(
    globus_callback_func_t              callback,
    void *                              user_arg)
{
    globus_l_xio_win32_poll_entry_t *   entry;
    globus_result_t                     result;
    GlobusXIOName(globus_i_xio_win32_complete);

    GlobusXIOSystemDebugEnter();
    
    if (! globus_i_am_only_thread())
    {
        return globus_callback_register_oneshot(
            0,
            0,
            callback,
            user_arg);
    }

    win32_mutex_lock(&globus_l_xio_win32_poll_lock);
    {
        if(globus_l_xio_win32_poll_free)
        {
            entry = globus_l_xio_win32_poll_free;
            globus_l_xio_win32_poll_free = entry->next;
        }
        else
        {
            entry = (globus_l_xio_win32_poll_entry_t *)
                globus_malloc(sizeof(globus_l_xio_win32_poll_entry_t));
            if(!entry)
            {
                result = GlobusXIOErrorMemory("entry");
                goto error_malloc;
            }
        }
        
        entry->callback = callback;
        entry->user_arg = user_arg;
    
        GlobusLWin32PollQueueEnqueue(entry);
        
        if(globus_l_xio_win32_poll_event_sleeping &&
            !globus_l_xio_win32_poll_event_pending)
        {
            SetEvent(globus_l_xio_win32_poll_event);
            globus_l_xio_win32_poll_event_pending = GLOBUS_TRUE;
        }
    }
    win32_mutex_unlock(&globus_l_xio_win32_poll_lock);
    
    GlobusXIOSystemDebugExit();

    return GLOBUS_SUCCESS;

error_malloc:
    return result;
}
Beispiel #2
0
void
cc_mutex_unlock(cc_mutex * mutex)
{
  int ok;
  assert(mutex != NULL);
#ifdef USE_W32THREAD
  if (cc_mutex_TryEnterCriticalSection)
    ok = win32_cs_unlock(mutex);
  else 
    ok = win32_mutex_unlock(mutex);
#else /* USE_W32THREAD */  
  ok = internal_mutex_unlock(mutex);
#endif /* USE_W32THREAD */

  assert(ok == CC_OK);
}
static
globus_result_t
globus_l_xio_win32_socket_register_write(
    globus_l_xio_win32_socket_t *       handle,
    globus_i_xio_system_op_info_t *     write_info)
{
    globus_result_t                     result;
    GlobusXIOName(globus_l_xio_win32_socket_register_write);
    
    GlobusXIOSystemDebugEnterFD(handle->socket);
    
    /* I have to do this outside the lock because of lock inversion issues */
    if(write_info->op && globus_xio_operation_enable_cancel(
        write_info->op, globus_l_xio_win32_socket_cancel_cb, write_info))
    {
        result = GlobusXIOErrorCanceled();
        goto error_cancel_enable;
    }

    win32_mutex_lock(&handle->lock);
    {
        if(write_info->state == GLOBUS_I_XIO_SYSTEM_OP_CANCELED)
        {
            result = globus_error_put(write_info->error);
            goto error_canceled;
        }

        if(handle->write_info)
        {
            result = GlobusXIOErrorAlreadyRegistered();
            goto error_already_registered;
        }
        
        write_info->state = GLOBUS_I_XIO_SYSTEM_OP_PENDING;
        /* if select() functionality requested, only handle after we receive
         * write event
         * 
         * also dont call for connect operations.  waitforbytes == 0 in this
         * case and handle->ready_events should not yet have a write event
         */
        if(write_info->waitforbytes > 0 || handle->ready_events & FD_WRITE)
        {
            globus_l_xio_win32_socket_handle_write(handle, write_info);
        }
        
        if(write_info->state != GLOBUS_I_XIO_SYSTEM_OP_COMPLETE)
        {
            /* make sure we're set up to be notified of events */
            long needevents;
            
            if(write_info->type == GLOBUS_I_XIO_SYSTEM_OP_CONNECT)
            {
                needevents = FD_CONNECT|FD_CLOSE;
            }
            else
            {
                needevents = FD_WRITE|FD_CLOSE;
            }
            
            if((handle->eventselect & needevents) != needevents)
            {
                if(WSAEventSelect(
                    handle->socket, handle->event,
                    handle->eventselect|needevents) == SOCKET_ERROR)
                {
                    write_info->error = GlobusXIOErrorObjSystemError(
                        "WSAEventSelect", WSAGetLastError());
                }
                else
                {
                    handle->eventselect |= needevents;
                }
            }
            
            if(!write_info->error)
            {
                handle->write_info = write_info;
                write_info = 0;
            }
        }
    }
    win32_mutex_unlock(&handle->lock);
    
    /* do this outside the lock to avoid unnecessary contention */
    if(write_info)
    {
        globus_l_xio_win32_socket_complete(write_info, GLOBUS_FALSE);
    }

    GlobusXIOSystemDebugExitFD(handle->socket);
    return GLOBUS_SUCCESS;

error_already_registered:
error_canceled:
    write_info->state = GLOBUS_I_XIO_SYSTEM_OP_COMPLETE;
    win32_mutex_unlock(&handle->lock);
    if(write_info->op)
    {
        globus_xio_operation_disable_cancel(write_info->op);
    }
error_cancel_enable:
    GlobusXIOSystemDebugExitWithErrorFD(handle->socket);
    return result;
}
/* always called from win32 thread */
static
globus_bool_t
globus_l_xio_win32_socket_event_cb(
    void *                              user_arg)
{
    globus_l_xio_win32_socket_t *       handle;
    WSANETWORKEVENTS                    wsaevents;
    long                                events;
    long                                clearevents = 0;
    globus_i_xio_system_op_info_t *     read_info = 0;
    globus_i_xio_system_op_info_t *     write_info = 0;
    GlobusXIOName(globus_l_xio_win32_socket_event_cb);
    
    handle = (globus_l_xio_win32_socket_t *) user_arg;
    
    GlobusXIOSystemDebugEnterFD(handle->socket);
    
    if(WSAEnumNetworkEvents(
        handle->socket, handle->event, &wsaevents) == SOCKET_ERROR)
    {
        GlobusXIOSystemDebugSysError(
            "WSAEnumNetworkEvents error", WSAGetLastError());
        goto error_enum;
    }
    
    events = wsaevents.lNetworkEvents;
    win32_mutex_lock(&handle->lock);
    {
        GlobusXIOSystemDebugPrintf(
            GLOBUS_I_XIO_SYSTEM_DEBUG_INFO,
            ("[%s] Ready events: %s%s%s%s%s fd=%lu\n", _xio_name,
                events & FD_ACCEPT  ? "accept;"     : "",
                events & FD_CONNECT ? "connect;"    : "",
                events & FD_READ    ? "read;"       : "",
                events & FD_WRITE   ? "write;"      : "",
                events & FD_CLOSE   ? "close;"      : "",
                (unsigned long)handle->socket));
        
        if(events & (FD_ACCEPT|FD_READ|FD_CLOSE))
        {
            /* cache for select() like functionality */
            handle->ready_events |= FD_READ;
                
            if(handle->read_info)
            {
                globus_l_xio_win32_socket_handle_read(
                    handle, handle->read_info);
                    
                if(handle->read_info->state == GLOBUS_I_XIO_SYSTEM_OP_COMPLETE)
                {
                    read_info = handle->read_info;
                    handle->read_info = 0;
                }
            }
            else
            {
                clearevents |= FD_ACCEPT|FD_READ;
            }
        }
        
        if(events & (FD_CONNECT|FD_WRITE|FD_CLOSE))
        {
            /* cache for select() like functionality */
            handle->ready_events |= FD_WRITE;
                
            if(handle->write_info)
            {
                globus_l_xio_win32_socket_handle_write(
                    handle, handle->write_info);
                    
                if(handle->write_info->state ==
                    GLOBUS_I_XIO_SYSTEM_OP_COMPLETE)
                {
                    write_info = handle->write_info;
                    handle->write_info = 0;
                }
            }
            else
            {
                clearevents |= FD_CONNECT|FD_WRITE;
            }
        }
        
        /* clear any events we want to ignore */
        if((handle->eventselect & clearevents))
        {
            handle->eventselect &= ~clearevents;
            WSAEventSelect(handle->socket, handle->event, handle->eventselect);
        }
    }
    win32_mutex_unlock(&handle->lock);

    /* do this outside the lock to avoid unnecessary contention */
    if(read_info)
    {
        globus_l_xio_win32_socket_complete(read_info, GLOBUS_TRUE);
    }
    
    if(write_info)
    {
        globus_l_xio_win32_socket_complete(write_info, GLOBUS_TRUE);
    }

    GlobusXIOSystemDebugExitFD(handle->socket);
    return GLOBUS_TRUE;

error_enum:
    GlobusXIOSystemDebugExitWithErrorFD(handle->socket);
    return GLOBUS_TRUE;
}
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_system_socket_write(
    globus_xio_system_socket_handle_t   handle,
    const globus_xio_iovec_t *          iov,
    int                                 iovc,
    globus_size_t                       waitforbytes,
    int                                 flags,
    globus_sockaddr_t *                 to,
    globus_size_t *                     nbytes)
{
    globus_result_t                     result;
    globus_l_xio_win32_blocking_info_t * blocking_info;
    GlobusXIOName(globus_xio_system_socket_write);
    
    GlobusXIOSystemDebugEnterFD(handle->socket);
    GlobusXIOSystemDebugPrintf(
        GLOBUS_I_XIO_SYSTEM_DEBUG_DATA,
        ("[%s] Waiting for %ld bytes\n", _xio_name, (long) waitforbytes));
    
    win32_mutex_lock(&handle->lock);
    {
        result = globus_i_xio_system_socket_try_write(
            handle->socket,
            iov,
            iovc,
            flags,
            to,
            nbytes);
    }
    win32_mutex_unlock(&handle->lock);
    
    if(result == GLOBUS_SUCCESS && *nbytes < waitforbytes)
    {
        result = globus_l_xio_win32_blocking_init(&blocking_info);
        if(result != GLOBUS_SUCCESS)
        {
            result = GlobusXIOErrorWrapFailed(
                "globus_l_xio_win32_blocking_init", result);
            goto error_init;
        }
        
        result = globus_l_xio_system_socket_register_write(
            0,
            handle,
            iov,
            iovc,
            waitforbytes,
            *nbytes,
            flags,
            to,
            globus_l_xio_win32_blocking_cb,
            blocking_info);
        if(result != GLOBUS_SUCCESS)
        {
            result = GlobusXIOErrorWrapFailed(
                "globus_l_xio_system_socket_register_write", result);
            goto error_register;
        }
        
        while(WaitForSingleObject(
            blocking_info->event, INFINITE) != WAIT_OBJECT_0) {}
        
        if(blocking_info->error)
        {
            result = globus_error_put(blocking_info->error);
        }
        *nbytes = blocking_info->nbytes;
        
        globus_l_xio_win32_blocking_destroy(blocking_info);
    }

    GlobusXIOSystemDebugExitFD(handle->socket);
    return result;

error_register:
    globus_l_xio_win32_blocking_destroy(blocking_info);
error_init:
    GlobusXIOSystemDebugExitWithErrorFD(handle->socket);
    return result;
}
static
void
globus_l_xio_win32_poll(
    void *                              user_arg)
{
    GlobusXIOName(globus_l_xio_win32_poll);

    GlobusXIOSystemDebugEnter();

    win32_mutex_lock(&globus_l_xio_win32_poll_lock);
    {
        if(GlobusLWin32PollQueueEmpty())
        {
            globus_reltime_t            time_left;
            
            globus_callback_get_timeout(&time_left);
            if(globus_reltime_cmp(&time_left, &globus_i_reltime_zero) > 0)
            {
                DWORD                   millis = INFINITE;
                
                if(!globus_time_reltime_is_infinity(&time_left))
                {
                    GlobusTimeReltimeToMilliSec(millis, time_left);
                }
                
                globus_l_xio_win32_poll_event_sleeping = GLOBUS_TRUE;
                win32_mutex_unlock(&globus_l_xio_win32_poll_lock);
                
                WaitForSingleObject(globus_l_xio_win32_poll_event, millis);
                
                win32_mutex_lock(&globus_l_xio_win32_poll_lock);
                globus_l_xio_win32_poll_event_sleeping = GLOBUS_FALSE;
                globus_l_xio_win32_poll_event_pending = GLOBUS_FALSE;
            }
        }
        
        while(!GlobusLWin32PollQueueEmpty())
        {
            globus_l_xio_win32_poll_entry_t * entry;
            
            GlobusLWin32PollQueueDequeue(entry);
            
            win32_mutex_unlock(&globus_l_xio_win32_poll_lock);
                
            entry->callback(entry->user_arg);
            
            win32_mutex_lock(&globus_l_xio_win32_poll_lock);
            
            entry->next = globus_l_xio_win32_poll_free;
            globus_l_xio_win32_poll_free = entry;
            
            if(globus_callback_has_time_expired())
            {
                break;
            }
        }
    }
    win32_mutex_unlock(&globus_l_xio_win32_poll_lock);

    GlobusXIOSystemDebugExit();
}