[reflection] Use coop handles for MonoMethod icalls (#4272)
[mono.git] / mono / io-layer / io.c
index 8ec7c50ae58ac61949a50fe4b3d51f45278dff33..05d554a12c0c621abf4b44aabf6239d36781301b 100644 (file)
 #include <mono/io-layer/wapi.h>
 #include <mono/io-layer/wapi-private.h>
 #include <mono/io-layer/io-private.h>
-#include <mono/io-layer/timefuncs-private.h>
-#include <mono/io-layer/thread-private.h>
 #include <mono/io-layer/io-portability.h>
 #include <mono/io-layer/io-trace.h>
 #include <mono/utils/strenc.h>
 #include <mono/utils/mono-once.h>
 #include <mono/utils/mono-logger-internals.h>
-#include <mono/utils/w32handle.h>
+#include <mono/metadata/w32handle.h>
 
 /*
  * If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise
  * 4MB array.
  */
 static GHashTable *file_share_hash;
-static mono_mutex_t file_share_hash_mutex;
+static mono_mutex_t file_share_mutex;
 
-#define file_share_hash_lock() mono_os_mutex_lock (&file_share_hash_mutex)
-#define file_share_hash_unlock() mono_os_mutex_unlock (&file_share_hash_mutex)
+static void
+time_t_to_filetime (time_t timeval, WapiFileTime *filetime)
+{
+       guint64 ticks;
+       
+       ticks = ((guint64)timeval * 10000000) + 116444736000000000ULL;
+       filetime->dwLowDateTime = ticks & 0xFFFFFFFF;
+       filetime->dwHighDateTime = ticks >> 32;
+}
 
 static void
 _wapi_handle_share_release (_WapiFileShare *share_info)
 {
-       int thr_ret;
+       /* Prevent new entries racing with us */
+       mono_os_mutex_lock (&file_share_mutex);
 
        g_assert (share_info->handle_refs > 0);
-       
-       /* Prevent new entries racing with us */
-       thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
-       g_assert(thr_ret == 0);
+       share_info->handle_refs -= 1;
 
-       if (InterlockedDecrement ((gint32 *)&share_info->handle_refs) == 0) {
-               file_share_hash_lock ();
+       if (share_info->handle_refs == 0)
                g_hash_table_remove (file_share_hash, share_info);
-               file_share_hash_unlock ();
-       }
 
-       thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
-       g_assert (thr_ret == 0);
+       mono_os_mutex_unlock (&file_share_mutex);
 }
 
 static gint
@@ -102,12 +101,10 @@ _wapi_handle_get_or_set_share (guint64 device, guint64 inode, guint32 new_sharem
        guint32 *old_sharemode, guint32 *old_access, struct _WapiFileShare **share_info)
 {
        struct _WapiFileShare *file_share;
-       int thr_ret;
        gboolean exists = FALSE;
 
        /* Prevent new entries racing with us */
-       thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
-       g_assert (thr_ret == 0);
+       mono_os_mutex_lock (&file_share_mutex);
 
        _WapiFileShare tmp;
 
@@ -116,30 +113,28 @@ _wapi_handle_get_or_set_share (guint64 device, guint64 inode, guint32 new_sharem
         * info. This is needed even if SHM is disabled, to track sharing inside
         * the current process.
         */
-       if (!file_share_hash) {
+       if (!file_share_hash)
                file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
-               mono_os_mutex_init_recursive (&file_share_hash_mutex);
-       }
 
        tmp.device = device;
        tmp.inode = inode;
 
-       file_share_hash_lock ();
-
        file_share = (_WapiFileShare *)g_hash_table_lookup (file_share_hash, &tmp);
        if (file_share) {
                *old_sharemode = file_share->sharemode;
                *old_access = file_share->access;
                *share_info = file_share;
 
-               InterlockedIncrement ((gint32 *)&file_share->handle_refs);
+               g_assert (file_share->handle_refs > 0);
+               file_share->handle_refs += 1;
+
                exists = TRUE;
        } else {
                file_share = g_new0 (_WapiFileShare, 1);
 
                file_share->device = device;
                file_share->inode = inode;
-               file_share->opened_by_pid = _wapi_getpid ();
+               file_share->opened_by_pid = wapi_getpid ();
                file_share->sharemode = new_sharemode;
                file_share->access = new_access;
                file_share->handle_refs = 1;
@@ -148,10 +143,7 @@ _wapi_handle_get_or_set_share (guint64 device, guint64 inode, guint32 new_sharem
                g_hash_table_insert (file_share_hash, file_share, file_share);
        }
 
-       file_share_hash_unlock ();
-       
-       thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
-       g_assert (thr_ret == 0);
+       mono_os_mutex_unlock (&file_share_mutex);
 
        return(exists);
 }
@@ -513,6 +505,7 @@ static gboolean file_read(gpointer handle, gpointer buffer,
        struct _WapiHandle_file *file_handle;
        gboolean ok;
        int fd, ret;
+       MonoThreadInfo *info = mono_thread_info_current ();
        
        ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -540,7 +533,7 @@ static gboolean file_read(gpointer handle, gpointer buffer,
        do {
                ret = read (fd, buffer, numbytes);
        } while (ret == -1 && errno == EINTR &&
-                !_wapi_thread_cur_apc_pending());
+                !mono_thread_info_is_interrupt_state (info));
                        
        if(ret==-1) {
                gint err = errno;
@@ -566,6 +559,7 @@ static gboolean file_write(gpointer handle, gconstpointer buffer,
        gboolean ok;
        int ret, fd;
        off_t current_pos = 0;
+       MonoThreadInfo *info = mono_thread_info_current ();
        
        ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -613,7 +607,7 @@ static gboolean file_write(gpointer handle, gconstpointer buffer,
        do {
                ret = write (fd, buffer, numbytes);
        } while (ret == -1 && errno == EINTR &&
-                !_wapi_thread_cur_apc_pending());
+                !mono_thread_info_is_interrupt_state (info));
        
        if (lock_while_writing) {
                _wapi_unlock_file_region (fd, current_pos, numbytes);
@@ -779,6 +773,7 @@ static gboolean file_setendoffile(gpointer handle)
        struct stat statbuf;
        off_t pos;
        int ret, fd;
+       MonoThreadInfo *info = mono_thread_info_current ();
        
        ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -839,7 +834,7 @@ static gboolean file_setendoffile(gpointer handle)
                do {
                        ret = write (fd, "", 1);
                } while (ret == -1 && errno == EINTR &&
-                        !_wapi_thread_cur_apc_pending());
+                        !mono_thread_info_is_interrupt_state (info));
 
                if(ret==-1) {
                        MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p extend write failed: %s", __func__, handle, strerror(errno));
@@ -868,7 +863,7 @@ static gboolean file_setendoffile(gpointer handle)
        do {
                ret=ftruncate(fd, pos);
        }
-       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending()); 
+       while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info)); 
        if(ret==-1) {
                MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p ftruncate failed: %s", __func__,
                          handle, strerror(errno));
@@ -1202,6 +1197,7 @@ static gboolean console_read(gpointer handle, gpointer buffer,
        struct _WapiHandle_file *console_handle;
        gboolean ok;
        int ret, fd;
+       MonoThreadInfo *info = mono_thread_info_current ();
 
        ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_CONSOLE,
                                (gpointer *)&console_handle);
@@ -1228,7 +1224,7 @@ static gboolean console_read(gpointer handle, gpointer buffer,
        
        do {
                ret=read(fd, buffer, numbytes);
-       } while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+       } while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info));
 
        if(ret==-1) {
                MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: read of handle %p error: %s", __func__, handle,
@@ -1252,6 +1248,7 @@ static gboolean console_write(gpointer handle, gconstpointer buffer,
        struct _WapiHandle_file *console_handle;
        gboolean ok;
        int ret, fd;
+       MonoThreadInfo *info = mono_thread_info_current ();
        
        ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_CONSOLE,
                                (gpointer *)&console_handle);
@@ -1278,7 +1275,7 @@ static gboolean console_write(gpointer handle, gconstpointer buffer,
        do {
                ret = write(fd, buffer, numbytes);
        } while (ret == -1 && errno == EINTR &&
-                !_wapi_thread_cur_apc_pending());
+                !mono_thread_info_is_interrupt_state (info));
 
        if (ret == -1) {
                if (errno == EINTR) {
@@ -1351,6 +1348,7 @@ static gboolean pipe_read (gpointer handle, gpointer buffer,
        struct _WapiHandle_file *pipe_handle;
        gboolean ok;
        int ret, fd;
+       MonoThreadInfo *info = mono_thread_info_current ();
 
        ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_PIPE,
                                (gpointer *)&pipe_handle);
@@ -1380,7 +1378,7 @@ static gboolean pipe_read (gpointer handle, gpointer buffer,
 
        do {
                ret=read(fd, buffer, numbytes);
-       } while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+       } while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info));
                
        if (ret == -1) {
                if (errno == EINTR) {
@@ -1411,6 +1409,7 @@ static gboolean pipe_write(gpointer handle, gconstpointer buffer,
        struct _WapiHandle_file *pipe_handle;
        gboolean ok;
        int ret, fd;
+       MonoThreadInfo *info = mono_thread_info_current ();
        
        ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_PIPE,
                                (gpointer *)&pipe_handle);
@@ -1440,7 +1439,7 @@ static gboolean pipe_write(gpointer handle, gconstpointer buffer,
        do {
                ret = write (fd, buffer, numbytes);
        } while (ret == -1 && errno == EINTR &&
-                !_wapi_thread_cur_apc_pending());
+                !mono_thread_info_is_interrupt_state (info));
 
        if (ret == -1) {
                if (errno == EINTR) {
@@ -1774,7 +1773,12 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
        if (attrs & FILE_FLAG_RANDOM_ACCESS)
                posix_fadvise (fd, 0, 0, POSIX_FADV_RANDOM);
 #endif
-       
+
+#ifdef F_RDAHEAD
+       if (attrs & FILE_FLAG_SEQUENTIAL_SCAN)
+               fcntl(fd, F_RDAHEAD, 1);
+#endif
+
 #ifndef S_ISFIFO
 #define S_ISFIFO(m) ((m & S_IFIFO) != 0)
 #endif
@@ -1988,9 +1992,14 @@ gboolean MoveFile (const gunichar2 *name, const gunichar2 *dest_name)
                case EXDEV:
                        /* Ignore here, it is dealt with below */
                        break;
-                       
+
+               case ENOENT:
+                       /* We already know src exists. Must be dest that doesn't exist. */
+                       _wapi_set_last_path_error_from_errno (NULL, utf8_dest_name);
+                       break;
+
                default:
-                       _wapi_set_last_path_error_from_errno (NULL, utf8_name);
+                       _wapi_set_last_error_from_errno ();
                }
        }
        
@@ -2024,20 +2033,21 @@ write_file (int src_fd, int dest_fd, struct stat *st_src, gboolean report_errors
        int remain, n;
        char *buf, *wbuf;
        int buf_size = st_src->st_blksize;
+       MonoThreadInfo *info = mono_thread_info_current ();
 
        buf_size = buf_size < 8192 ? 8192 : (buf_size > 65536 ? 65536 : buf_size);
-       buf = (char *) malloc (buf_size);
+       buf = (char *) g_malloc (buf_size);
 
        for (;;) {
                remain = read (src_fd, buf, buf_size);
                if (remain < 0) {
-                       if (errno == EINTR && !_wapi_thread_cur_apc_pending ())
+                       if (errno == EINTR && !mono_thread_info_is_interrupt_state (info))
                                continue;
 
                        if (report_errors)
                                _wapi_set_last_error_from_errno ();
 
-                       free (buf);
+                       g_free (buf);
                        return FALSE;
                }
                if (remain == 0) {
@@ -2047,13 +2057,13 @@ write_file (int src_fd, int dest_fd, struct stat *st_src, gboolean report_errors
                wbuf = buf;
                while (remain > 0) {
                        if ((n = write (dest_fd, wbuf, remain)) < 0) {
-                               if (errno == EINTR && !_wapi_thread_cur_apc_pending ())
+                               if (errno == EINTR && !mono_thread_info_is_interrupt_state (info))
                                        continue;
 
                                if (report_errors)
                                        _wapi_set_last_error_from_errno ();
                                MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: write failed.", __func__);
-                               free (buf);
+                               g_free (buf);
                                return FALSE;
                        }
 
@@ -2062,7 +2072,7 @@ write_file (int src_fd, int dest_fd, struct stat *st_src, gboolean report_errors
                }
        }
 
-       free (buf);
+       g_free (buf);
        return TRUE ;
 }
 
@@ -2298,7 +2308,7 @@ gpointer GetStdHandle(WapiStdHandle stdhandle)
 {
        struct _WapiHandle_file *file_handle;
        gpointer handle;
-       int thr_ret, fd;
+       int fd;
        const gchar *name;
        gboolean ok;
        
@@ -2327,8 +2337,7 @@ gpointer GetStdHandle(WapiStdHandle stdhandle)
 
        handle = GINT_TO_POINTER (fd);
 
-       thr_ret = mono_os_mutex_lock (&stdhandle_mutex);
-       g_assert (thr_ret == 0);
+       mono_os_mutex_lock (&stdhandle_mutex);
 
        ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_CONSOLE,
                                  (gpointer *)&file_handle);
@@ -2346,8 +2355,7 @@ gpointer GetStdHandle(WapiStdHandle stdhandle)
        }
        
   done:
-       thr_ret = mono_os_mutex_unlock (&stdhandle_mutex);
-       g_assert (thr_ret == 0);
+       mono_os_mutex_unlock (&stdhandle_mutex);
        
        return(handle);
 }
@@ -2919,7 +2927,6 @@ gboolean FindNextFile (gpointer handle, WapiFindData *find_data)
        gunichar2 *utf16_basename;
        time_t create_time;
        glong bytes;
-       int thr_ret;
        gboolean ret = FALSE;
        
        ok=mono_w32handle_lookup (handle, MONO_W32HANDLE_FIND,
@@ -2931,8 +2938,7 @@ gboolean FindNextFile (gpointer handle, WapiFindData *find_data)
                return(FALSE);
        }
 
-       thr_ret = mono_w32handle_lock_handle (handle);
-       g_assert (thr_ret == 0);
+       mono_w32handle_lock_handle (handle);
        
 retry:
        if (find_handle->count >= find_handle->num) {
@@ -2995,9 +3001,9 @@ retry:
        find_data->dwFileAttributes = _wapi_stat_to_file_attributes (utf8_filename, &buf, &linkbuf);
 #endif
 
-       _wapi_time_t_to_filetime (create_time, &find_data->ftCreationTime);
-       _wapi_time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime);
-       _wapi_time_t_to_filetime (buf.st_mtime, &find_data->ftLastWriteTime);
+       time_t_to_filetime (create_time, &find_data->ftCreationTime);
+       time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime);
+       time_t_to_filetime (buf.st_mtime, &find_data->ftLastWriteTime);
 
        if (find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                find_data->nFileSizeHigh = 0;
@@ -3038,8 +3044,7 @@ retry:
        g_free (utf16_basename);
 
 cleanup:
-       thr_ret = mono_w32handle_unlock_handle (handle);
-       g_assert (thr_ret == 0);
+       mono_w32handle_unlock_handle (handle);
        
        return(ret);
 }
@@ -3056,7 +3061,6 @@ gboolean FindClose (gpointer handle)
 {
        struct _WapiHandle_find *find_handle;
        gboolean ok;
-       int thr_ret;
 
        if (handle == NULL) {
                SetLastError (ERROR_INVALID_HANDLE);
@@ -3072,14 +3076,12 @@ gboolean FindClose (gpointer handle)
                return(FALSE);
        }
 
-       thr_ret = mono_w32handle_lock_handle (handle);
-       g_assert (thr_ret == 0);
+       mono_w32handle_lock_handle (handle);
        
        g_strfreev (find_handle->namelist);
        g_free (find_handle->dir_part);
 
-       thr_ret = mono_w32handle_unlock_handle (handle);
-       g_assert (thr_ret == 0);
+       mono_w32handle_unlock_handle (handle);
        
        mono_w32handle_unref (handle);
        
@@ -3308,9 +3310,9 @@ gboolean GetFileAttributesEx (const gunichar2 *name, WapiGetFileExInfoLevels lev
 
        g_free (utf8_name);
 
-       _wapi_time_t_to_filetime (create_time, &data->ftCreationTime);
-       _wapi_time_t_to_filetime (buf.st_atime, &data->ftLastAccessTime);
-       _wapi_time_t_to_filetime (buf.st_mtime, &data->ftLastWriteTime);
+       time_t_to_filetime (create_time, &data->ftCreationTime);
+       time_t_to_filetime (buf.st_atime, &data->ftLastAccessTime);
+       time_t_to_filetime (buf.st_mtime, &data->ftLastWriteTime);
 
        if (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                data->nFileSizeHigh = 0;
@@ -4005,9 +4007,9 @@ GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf)
 #endif
 
 #if defined(HAVE_STATVFS) || defined(HAVE_STATFS)
-gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, WapiULargeInteger *free_bytes_avail,
-                           WapiULargeInteger *total_number_of_bytes,
-                           WapiULargeInteger *total_number_of_free_bytes)
+gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, ULARGE_INTEGER *free_bytes_avail,
+                           ULARGE_INTEGER *total_number_of_bytes,
+                           ULARGE_INTEGER *total_number_of_free_bytes)
 {
 #ifdef HAVE_STATVFS
        struct statvfs fsstat;
@@ -4088,9 +4090,9 @@ gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, WapiULargeInteger *free_
        return(TRUE);
 }
 #else
-gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, WapiULargeInteger *free_bytes_avail,
-                           WapiULargeInteger *total_number_of_bytes,
-                           WapiULargeInteger *total_number_of_free_bytes)
+gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, ULARGE_INTEGER *free_bytes_avail,
+                           ULARGE_INTEGER *total_number_of_bytes,
+                           ULARGE_INTEGER *total_number_of_free_bytes)
 {
        if (free_bytes_avail != NULL) {
                free_bytes_avail->QuadPart = (guint64) -1;
@@ -4425,6 +4427,7 @@ void
 _wapi_io_init (void)
 {
        mono_os_mutex_init (&stdhandle_mutex);
+       mono_os_mutex_init (&file_share_mutex);
 
        mono_w32handle_register_ops (MONO_W32HANDLE_FILE,    &_wapi_file_ops);
        mono_w32handle_register_ops (MONO_W32HANDLE_CONSOLE, &_wapi_console_ops);
@@ -4443,8 +4446,8 @@ _wapi_io_init (void)
 void
 _wapi_io_cleanup (void)
 {
-       if (file_share_hash) {
+       mono_os_mutex_destroy (&file_share_mutex);
+
+       if (file_share_hash)
                g_hash_table_destroy (file_share_hash);
-               mono_os_mutex_destroy (&file_share_hash_mutex);
-       }
 }