~ubuntu-branches/ubuntu/trusty/mariadb-5.5/trusty-proposed

« back to all changes in this revision

Viewing changes to mysys/my_lock.c

  • Committer: Package Import Robot
  • Author(s): Otto Kekäläinen
  • Date: 2013-12-22 10:27:05 UTC
  • Revision ID: package-import@ubuntu.com-20131222102705-mndw7s12mz0szrcn
Tags: upstream-5.5.32
Import upstream version 5.5.32

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
 
15
 
 
16
#include "mysys_priv.h"
 
17
#include "mysys_err.h"
 
18
#include <errno.h>
 
19
#undef MY_HOW_OFTEN_TO_ALARM
 
20
#define MY_HOW_OFTEN_TO_ALARM ((int) my_time_to_wait_for_lock)
 
21
#ifdef NO_ALARM_LOOP
 
22
#undef NO_ALARM_LOOP
 
23
#endif
 
24
#include <my_alarm.h>
 
25
 
 
26
#ifdef _WIN32
 
27
#define WIN_LOCK_INFINITE -1
 
28
#define WIN_LOCK_SLEEP_MILLIS 100
 
29
 
 
30
static int win_lock(File fd, int locktype, my_off_t start, my_off_t length,
 
31
                int timeout_sec)
 
32
{
 
33
  LARGE_INTEGER liOffset,liLength;
 
34
  DWORD dwFlags;
 
35
  OVERLAPPED ov= {0};
 
36
  HANDLE hFile= (HANDLE)my_get_osfhandle(fd);
 
37
  DWORD  lastError= 0;
 
38
  int i;
 
39
  int timeout_millis= timeout_sec * 1000;
 
40
 
 
41
  DBUG_ENTER("win_lock");
 
42
 
 
43
  liOffset.QuadPart= start;
 
44
  liLength.QuadPart= length;
 
45
 
 
46
  ov.Offset=      liOffset.LowPart;
 
47
  ov.OffsetHigh=  liOffset.HighPart;
 
48
 
 
49
  if (locktype == F_UNLCK)
 
50
  {
 
51
    if (UnlockFileEx(hFile, 0, liLength.LowPart, liLength.HighPart, &ov))
 
52
      DBUG_RETURN(0);
 
53
    /*
 
54
      For compatibility with fcntl implementation, ignore error,
 
55
      if region was not locked
 
56
    */
 
57
    if (GetLastError() == ERROR_NOT_LOCKED)
 
58
    {
 
59
      SetLastError(0);
 
60
      DBUG_RETURN(0);
 
61
    }
 
62
    goto error;
 
63
  }
 
64
  else if (locktype == F_RDLCK)
 
65
    /* read lock is mapped to a shared lock. */
 
66
    dwFlags= 0;
 
67
  else
 
68
    /* write lock is mapped to an exclusive lock. */
 
69
    dwFlags= LOCKFILE_EXCLUSIVE_LOCK;
 
70
 
 
71
  /*
 
72
    Drop old lock first to avoid double locking.
 
73
    During analyze of Bug#38133 (Myisamlog test fails on Windows)
 
74
    I met the situation that the program myisamlog locked the file
 
75
    exclusively, then additionally shared, then did one unlock, and
 
76
    then blocked on an attempt to lock it exclusively again.
 
77
    Unlocking before every lock fixed the problem.
 
78
    Note that this introduces a race condition. When the application
 
79
    wants to convert an exclusive lock into a shared one, it will now
 
80
    first unlock the file and then lock it shared. A waiting exclusive
 
81
    lock could step in here. For reasons described in Bug#38133 and
 
82
    Bug#41124 (Server hangs on Windows with --external-locking after
 
83
    INSERT...SELECT) and in the review thread at
 
84
    http://lists.mysql.com/commits/60721 it seems to be the better
 
85
    option than not to unlock here.
 
86
    If one day someone notices a way how to do file lock type changes
 
87
    on Windows without unlocking before taking the new lock, please
 
88
    change this code accordingly to fix the race condition.
 
89
  */
 
90
  if (!UnlockFileEx(hFile, 0, liLength.LowPart, liLength.HighPart, &ov) &&
 
91
      (GetLastError() != ERROR_NOT_LOCKED))
 
92
    goto error;
 
93
 
 
94
  if (timeout_sec == WIN_LOCK_INFINITE)
 
95
  {
 
96
    if (LockFileEx(hFile, dwFlags, 0, liLength.LowPart, liLength.HighPart, &ov))
 
97
      DBUG_RETURN(0);
 
98
    goto error;
 
99
  }
 
100
  
 
101
  dwFlags|= LOCKFILE_FAIL_IMMEDIATELY;
 
102
  timeout_millis= timeout_sec * 1000;
 
103
  /* Try lock in a loop, until the lock is acquired or timeout happens */
 
104
  for(i= 0; ;i+= WIN_LOCK_SLEEP_MILLIS)
 
105
  {
 
106
    if (LockFileEx(hFile, dwFlags, 0, liLength.LowPart, liLength.HighPart, &ov))
 
107
     DBUG_RETURN(0);
 
108
 
 
109
    if (GetLastError() != ERROR_LOCK_VIOLATION)
 
110
      goto error;
 
111
 
 
112
    if (i >= timeout_millis)
 
113
      break;
 
114
    Sleep(WIN_LOCK_SLEEP_MILLIS);
 
115
  }
 
116
 
 
117
  /* timeout */
 
118
  errno= EAGAIN;
 
119
  DBUG_RETURN(-1);
 
120
 
 
121
error:
 
122
   my_osmaperr(GetLastError());
 
123
   DBUG_RETURN(-1);
 
124
}
 
125
#endif
 
126
 
 
127
 
 
128
 
 
129
/* 
 
130
  Lock a part of a file 
 
131
 
 
132
  RETURN VALUE
 
133
    0   Success
 
134
    -1  An error has occured and 'my_errno' is set
 
135
        to indicate the actual error code.
 
136
*/
 
137
 
 
138
int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
 
139
            myf MyFlags)
 
140
{
 
141
#ifdef HAVE_FCNTL
 
142
  int value;
 
143
  ALARM_VARIABLES;
 
144
#endif
 
145
 
 
146
  DBUG_ENTER("my_lock");
 
147
  DBUG_PRINT("my",("fd: %d  Op: %d  start: %ld  Length: %ld  MyFlags: %d",
 
148
                   fd,locktype,(long) start,(long) length,MyFlags));
 
149
  if (my_disable_locking && ! (MyFlags & MY_FORCE_LOCK))
 
150
    DBUG_RETURN(0);
 
151
 
 
152
#if defined(_WIN32)
 
153
  {
 
154
    int timeout_sec;
 
155
    if (MyFlags & MY_NO_WAIT)
 
156
      timeout_sec= 0;
 
157
    else
 
158
      timeout_sec= WIN_LOCK_INFINITE;
 
159
 
 
160
    if (win_lock(fd, locktype, start, length, timeout_sec) == 0)
 
161
      DBUG_RETURN(0);
 
162
  }
 
163
#else
 
164
#if defined(HAVE_FCNTL)
 
165
  {
 
166
    struct flock lock;
 
167
 
 
168
    lock.l_type=   (short) locktype;
 
169
    lock.l_whence= SEEK_SET;
 
170
    lock.l_start=  (off_t) start;
 
171
    lock.l_len=    (off_t) length;
 
172
 
 
173
    if (MyFlags & (MY_NO_WAIT | MY_SHORT_WAIT))
 
174
    {
 
175
      if (fcntl(fd,F_SETLK,&lock) != -1)        /* Check if we can lock */
 
176
        DBUG_RETURN(0);                         /* Ok, file locked */
 
177
      if (MyFlags & MY_NO_WAIT)
 
178
      {
 
179
        my_errno= (errno == EACCES) ? EAGAIN : errno ? errno : -1;
 
180
        DBUG_RETURN(-1);
 
181
      }
 
182
 
 
183
      DBUG_PRINT("info",("Was locked, trying with alarm"));
 
184
      ALARM_INIT;
 
185
      while ((value=fcntl(fd,F_SETLKW,&lock)) && ! ALARM_TEST &&
 
186
             errno == EINTR)
 
187
      {                 /* Setup again so we don`t miss it */
 
188
        ALARM_REINIT;
 
189
      }
 
190
      ALARM_END;
 
191
      if (value != -1)
 
192
        DBUG_RETURN(0);
 
193
      if (errno == EINTR)
 
194
        errno=EAGAIN;
 
195
    }
 
196
    else if (fcntl(fd,F_SETLKW,&lock) != -1) /* Wait until a lock */
 
197
      DBUG_RETURN(0);
 
198
  }
 
199
#else
 
200
  if (MyFlags & MY_SEEK_NOT_DONE)
 
201
  {
 
202
    if (my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE))
 
203
        == MY_FILEPOS_ERROR)
 
204
    {
 
205
      /*
 
206
        If an error has occured in my_seek then we will already
 
207
        have an error code in my_errno; Just return error code.
 
208
      */
 
209
      DBUG_RETURN(-1);
 
210
    }
 
211
  }
 
212
  if (lockf(fd,locktype,length) != -1)
 
213
    DBUG_RETURN(0);
 
214
#endif /* HAVE_FCNTL */
 
215
#endif /* _WIN32 */
 
216
 
 
217
  /* We got an error. We don't want EACCES errors */
 
218
  my_errno=(errno == EACCES) ? EAGAIN : errno ? errno : -1;
 
219
 
 
220
  if (MyFlags & MY_WME)
 
221
  {
 
222
    if (locktype == F_UNLCK)
 
223
      my_error(EE_CANTUNLOCK,MYF(ME_BELL+ME_WAITTANG),my_errno);
 
224
    else
 
225
      my_error(EE_CANTLOCK,MYF(ME_BELL+ME_WAITTANG),my_errno);
 
226
  }
 
227
  DBUG_PRINT("error",("my_errno: %d (%d)",my_errno,errno));
 
228
  DBUG_RETURN(-1);
 
229
} /* my_lock */