Subversion Repositories Kolibri OS

Rev

Rev 5605 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
431 serge 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
5565 serge 3
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
431 serge 4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
6
;; Synhronization for MenuetOS.                                 ;;
7
;; Author: Halyavin Andrey, halyavin@land.ru                    ;;
8
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
9
 
593 mikedld 10
$Revision: 6078 $
11
 
5593 serge 12
align 4
13
;struct futex*  __fastcall create_futex(int *ptr)
14
create_futex:
15
        push    ecx
16
        mov     ecx, sizeof.FUTEX
17
        call    create_object
18
        pop     ecx
19
        test    eax, eax
20
        jz .fail
593 mikedld 21
 
5593 serge 22
        mov     [eax+FUTEX.magic], 'FUTX'
23
        mov     [eax+FUTEX.destroy], 0
24
        mov     [eax+FUTEX.pointer], ecx
25
        lea     ecx, [eax+FUTEX.wait_list]
26
        list_init ecx
27
        mov     [eax+FUTEX.flags], 0
28
.fail:
29
        ret
30
 
5597 serge 31
align 4
32
;int __fastcall destroy_futex(struct futex *futex)
33
destroy_futex:
34
        push    esi
35
        mov     esi, [current_process]
36
        mov     edx, [ecx+FUTEX.handle]
37
 
38
        pushfd
39
        cli
40
 
41
        lea     eax, [ecx+FUTEX.wait_list]
42
        cmp     eax, [eax+LHEAD.next]
43
        jne     .fail
44
 
45
        mov     eax, [esi+PROC.ht_next]
46
        mov     [esi+PROC.htab+edx*4], eax
47
        mov     [esi+PROC.ht_next], edx
48
        inc     [esi+PROC.ht_free]
49
 
50
        popfd
51
        pop     esi
52
 
53
        mov     eax, ecx
54
        call    free
55
        xor     eax, eax
56
        ret
57
 
58
.fail:
59
        popfd
60
        pop     esi
61
        mov     eax, -1
62
        ret
63
 
64
 
5593 serge 65
iglobal
66
align 4
67
f77call:
68
        dd f77.futex_init     ;0
5597 serge 69
        dd f77.futex_destroy  ;1
70
        dd f77.futex_wait     ;2
71
        dd f77.futex_wake     ;3
5593 serge 72
.end:
73
endg
74
 
75
align 4
76
sys_synchronization:
77
f77:
5597 serge 78
        test    ebx, ebx
79
        jz      .futex_init
80
 
5593 serge 81
        cmp     ebx, (f77call.end-f77call)/4
5597 serge 82
        jae     .fail
5593 serge 83
 
5597 serge 84
        cmp     ecx, STDERR_FILENO
85
        jbe     .fail
86
        cmp     ecx, (PROC.pdt_0 - PROC.htab)/4
87
        jae     .fail
88
 
5599 serge 89
        mov     edi, [current_process]
90
        mov     ebp, [edi+PROC.htab+ecx*4]
5597 serge 91
 
5599 serge 92
        cmp     [ebp+FUTEX.magic], 'FUTX'
5597 serge 93
        jne     .fail
5599 serge 94
        cmp     [ebp+FUTEX.handle], ecx
5597 serge 95
        jne     .fail
96
 
5593 serge 97
        jmp     dword [f77call+ebx*4]
98
 
99
.fail:
100
        mov     [esp+SYSCALL_STACK._eax], -1
101
        ret
102
 
103
align 4
104
.futex_init:
105
        call    create_futex
106
        test    eax, eax
107
        jz      @F
108
        mov     eax, [eax+FUTEX.handle]
109
@@:
110
        mov     [esp+SYSCALL_STACK._eax], eax
111
        ret
112
 
5597 serge 113
 
5593 serge 114
align 4
115
;ecx futex handle
5599 serge 116
;edi current process
117
;ebp futex object
5597 serge 118
.futex_destroy:
5599 serge 119
        mov     ecx, ebp
5597 serge 120
        call    destroy_futex
121
        mov     [esp+SYSCALL_STACK._eax], eax
122
        ret
123
 
124
align 4
125
;ecx futex handle
5593 serge 126
;edx control value
5599 serge 127
;esi timeout
128
;edi current process
129
;ebp futex object
5593 serge 130
.futex_wait:
5599 serge 131
        test    esi, esi
132
        jnz     .futex_wait_timeout
133
        mov     ecx, [ebp+FUTEX.pointer]
5593 serge 134
        mov     eax, edx
135
        lock cmpxchg [ecx], edx         ;wait until old_value == new_value
136
        jz .wait_slow
137
 
138
        mov     [esp+SYSCALL_STACK._eax], 0
139
        ret
140
 
141
.wait_slow:
142
        pushfd
143
        cli
144
 
145
        sub     esp, sizeof.MUTEX_WAITER
146
        mov     ebx, [TASK_BASE]
147
        mov     [esp+MUTEX_WAITER.task], ebx
5599 serge 148
        lea     esi, [ebp+FUTEX.wait_list]
5593 serge 149
 
150
        list_add_tail esp, esi      ;esp= new waiter, esi= list head
151
 
152
.again:
6078 serge 153
        mov     [ebx+TASKDATA.state], 1
5593 serge 154
        call    change_task
155
 
156
        lock cmpxchg [ecx], edx
157
        jz .again
158
 
159
        list_del esp
160
        add     esp, sizeof.MUTEX_WAITER
161
 
162
        popfd
163
        mov     [esp+SYSCALL_STACK._eax], 0
164
        ret
165
 
166
align 4
167
;ecx futex handle
5599 serge 168
;edx control value
169
;esi timeout
170
;edi current process
171
;ebp futex object
172
 
173
.futex_wait_timeout:
174
        mov     ecx, [ebp+FUTEX.pointer]
175
        mov     eax, edx
176
        lock cmpxchg [ecx], edx         ;wait until old_value == new_value
177
        jz .wait_slow_timeout
178
 
179
        mov     [esp+SYSCALL_STACK._eax], 0
180
        ret
181
 
182
align 4
183
.wait_test:
184
        xor     eax, eax
185
        ret
186
 
187
.wait_slow_timeout:
188
        pushfd
189
        cli
190
 
191
        sub     esp, sizeof.MUTEX_WAITER
192
 
193
        mov     ebx, [current_slot]
194
        mov     [ebx+APPDATA.wait_test], f77.wait_test
195
        mov     [ebx+APPDATA.wait_timeout], esi
196
        mov     [ebx+APPDATA.wait_param], ebp
197
        mov     eax, [timer_ticks]
198
        mov     [ebx+APPDATA.wait_begin], eax
199
        mov     eax, [TASK_BASE]
200
        mov     [eax+TASKDATA.state], 5
201
 
6078 serge 202
        mov     [esp+MUTEX_WAITER.task], eax
5599 serge 203
        lea     esi, [ebp+FUTEX.wait_list]
204
 
205
        list_add_tail esp, esi      ;esp= new waiter, esi= list head
206
 
207
.again_timeout:
208
        call    change_task
209
        mov     eax, [ebx+APPDATA.wait_param]
210
        test    eax, eax
211
        jz      .timeout
212
 
213
        lock cmpxchg [ecx], edx
214
        jz .again_timeout
215
@@:
216
        list_del esp
217
        add     esp, sizeof.MUTEX_WAITER
218
 
219
        popfd
220
        mov     [esp+SYSCALL_STACK._eax], 0
221
        ret
222
 
223
.timeout:
224
        list_del esp
225
        add     esp, sizeof.MUTEX_WAITER
226
 
227
        popfd
228
        mov     [esp+SYSCALL_STACK._eax], -1
229
        ret
230
 
231
 
232
align 4
233
;ecx futex handle
5605 serge 234
;edx numder of threads
235
;edi current process
236
;ebp futex object
5593 serge 237
.futex_wake:
238
 
239
        xor     ecx, ecx
240
 
241
        pushfd
242
        cli
243
 
5605 serge 244
        lea     ebx, [ebp+FUTEX.wait_list]
5597 serge 245
        mov     esi, [ebx+LHEAD.next]
5605 serge 246
.wake:
5593 serge 247
        cmp     esi, ebx
5605 serge 248
        je      .done
5593 serge 249
 
250
        mov     eax, [esi+MUTEX_WAITER.task]
251
        mov     [eax+TASKDATA.state], 0
252
 
253
        mov     esi, [esi+MUTEX_WAITER.list.next]
254
        inc     ecx
255
        cmp     ecx, edx
5605 serge 256
        jb      .wake
257
.done:
5593 serge 258
        popfd
259
        mov     [esp+SYSCALL_STACK._eax], ecx
260
        ret
261
 
262
RWSEM_WAITING_FOR_WRITE equ 0
263
RWSEM_WAITING_FOR_READ  equ 1
264
 
265
;void  __fastcall mutex_init(struct mutex *lock)
266
 
267
align 4
268
mutex_init:
269
        mov     [ecx+MUTEX.wait_list.next], ecx
270
        mov     [ecx+MUTEX.wait_list.prev], ecx
271
        mov     [ecx+MUTEX.count], 1
272
        ret
273
 
274
;void  __fastcall mutex_lock(struct mutex *lock)
275
 
276
align 4
277
mutex_lock:
278
 
279
        dec     [ecx+MUTEX.count]
280
        jns     .done
281
 
282
        pushfd
283
        cli
284
 
285
        sub     esp, sizeof.MUTEX_WAITER
286
 
287
        list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
288
 
289
        mov     edx, [TASK_BASE]
290
        mov     [esp+MUTEX_WAITER.task], edx
291
 
292
.forever:
293
 
294
        mov     eax, -1
295
        xchg    eax, [ecx+MUTEX.count]
296
        dec     eax
297
        jz      @F
298
 
299
        mov     [edx+TASKDATA.state], 1
300
        call    change_task
301
        jmp     .forever
302
@@:
303
        mov     eax, ecx
304
        list_del esp
305
 
306
        cmp     [eax+MUTEX.wait_list.next], eax
307
        jne     @F
308
 
309
        mov     [eax+MUTEX.count], 0
310
@@:
311
        add     esp, sizeof.MUTEX_WAITER
312
 
313
        popfd
314
.done:
315
        ret
316
 
317
;void  __fastcall mutex_unlock(struct mutex *lock)
318
 
319
align 4
320
mutex_unlock:
321
 
322
        pushfd
323
        cli
324
 
325
        mov     eax, [ecx+MUTEX.wait_list.next]
326
        cmp     eax, ecx
327
        mov     [ecx+MUTEX.count], 1
328
        je      @F
329
 
330
        mov     eax, [eax+MUTEX_WAITER.task]
331
        mov     [eax+TASKDATA.state], 0
332
@@:
333
        popfd
334
        ret
335
 
336
 
337
;void __fastcall init_rwsem(struct rw_semaphore *sem)
338
 
339
align 4
340
init_rwsem:
341
        mov     [ecx+RWSEM.wait_list.next], ecx
342
        mov     [ecx+RWSEM.wait_list.prev], ecx
343
        mov     [ecx+RWSEM.count], 0
344
        ret
345
 
346
;void __fastcall down_read(struct rw_semaphore *sem)
347
 
348
align 4
349
down_read:
350
        pushfd
351
        cli
352
 
353
        mov     eax, [ecx+RWSEM.count]
354
        test    eax, eax
355
        js      @F
356
 
357
        cmp     ecx, [ecx+RWSEM.wait_list.next]
358
        je      .ok
359
@@:
360
        sub     esp, sizeof.MUTEX_WAITER
361
 
362
        mov     eax, [TASK_BASE]
363
        mov     [esp+MUTEX_WAITER.task], eax
364
        mov     [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_READ
365
        mov     [eax+TASKDATA.state], 1
366
 
367
        list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
368
 
369
        call    change_task
370
 
371
        add     esp, sizeof.MUTEX_WAITER
372
        popfd
373
        ret
374
.ok:
375
        inc     eax
376
        mov     [ecx+RWSEM.count], eax
377
 
378
        popfd
379
        ret
380
 
381
;void __fastcall down_write(struct rw_semaphore *sem)
382
 
383
align 4
384
down_write:
385
        pushfd
386
        cli
387
        sub     esp, sizeof.MUTEX_WAITER
388
 
389
        mov     edx, [TASK_BASE]
390
        mov     [esp+MUTEX_WAITER.task], edx
391
        mov     [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_WRITE
392
        mov     [edx+TASKDATA.state], 1
393
 
394
        list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
395
 
396
        xor     eax, eax
397
        not     eax
398
 
399
.forever:
400
        test    eax, [ecx+RWSEM.count]
401
        jz      @F
402
 
403
        mov     [edx+TASKDATA.state], 1
404
        call    change_task
405
        jmp     .forever
406
@@:
407
        mov     [ecx+RWSEM.count], eax
408
        list_del esp
409
 
410
        add     esp, sizeof.MUTEX_WAITER
411
        popfd
412
        ret
413
 
414
;void __fastcall up_read(struct rw_semaphore *sem)
415
 
416
align 4
417
up_read:
418
        pushfd
419
        cli
420
 
421
        dec     [ecx+RWSEM.count]
422
        jnz     @F
423
 
424
        mov     eax, [ecx+RWSEM.wait_list.next]
425
        cmp     eax, ecx
426
        je      @F
427
 
428
        mov     eax, [eax+MUTEX_WAITER.task]
429
        mov     [eax+TASKDATA.state], 0
430
@@:
431
        popfd
432
        ret
433
 
434
;void __fastcall up_write(struct rw_semaphore *sem)
435
 
436
align 4
437
up_write:
438
 
439
        pushfd
440
        cli
441
 
442
        mov     eax, [ecx+RWSEM.wait_list.next]
443
        mov     [ecx+RWSEM.count], 0
444
 
445
        cmp     ecx, eax
446
        je      .done
447
 
448
        mov     edx, [eax+MUTEX_WAITER.type]
449
        test    edx, edx
450
        jnz     .wake
451
 
452
        mov     eax, [eax+MUTEX_WAITER.task]
453
        mov     [eax+TASKDATA.state], 0
454
.done:
455
        popfd
456
        ret
457
 
458
.wake:
459
        push    ebx
460
        push    esi
461
        push    edi
462
 
463
        xor     esi, esi
464
        mov     edi, ecx
465
 
466
.wake_list:
467
 
468
        mov     ebx, [eax+MUTEX_WAITER.list.next]
469
        list_del eax
470
        mov     edx, [eax+MUTEX_WAITER.task]
471
        mov     [edx+TASKDATA.state], 0
472
        inc     esi
473
        cmp     edi, ebx
474
        je      .wake_done
475
 
476
        mov     ecx, [ebx+MUTEX_WAITER.type]
477
        test    ecx, ecx
478
        jz      .wake_done
479
 
480
        mov     eax, ebx
481
        jmp     .wake_list
482
 
483
.wake_done:
484
        add     [edi+RWSEM.count], esi
485
 
486
        pop     edi
487
        pop     esi
488
        pop     ebx
489
        popfd
490
        ret
491
 
492
 
493
purge RWSEM_WAITING_FOR_WRITE
494
purge RWSEM_WAITING_FOR_READ
495
 
496
 
1 ha 497
if ~defined sync_inc
498
sync_inc_fix:
499
sync_inc fix sync_inc_fix
500
 
501
;simplest mutex.
502
macro SimpleMutex name
503
{
504
;  iglobal
505
    name dd 0
506
    name#.type = 1
507
;  endg
508
}
509
macro WaitSimpleMutex name
510
{
511
  local start_wait,ok
379 serge 512
start_wait=$
2434 Serge 513
        cli
514
        cmp     [name], dword 0
515
        jz      ok
516
        sti
517
        call    change_task
518
        jmp     start_wait
1 ha 519
ok=$
2434 Serge 520
        push    eax
521
        mov     eax, dword [TASK_BASE+second_base_address]
522
        mov     eax, [eax+TASKDATA.pid]
523
        mov     [name], eax
524
        pop     eax
525
        sti
1 ha 526
}
527
macro ReleaseSimpleMutex name
528
{
2434 Serge 529
        mov     [name], dword 0
1 ha 530
}
531
macro TryWaitSimpleMutex name  ;result in eax and in flags
532
{
533
  local ok,try_end
2434 Serge 534
        cmp     [name], dword 0
535
        jz      ok
536
        xor     eax, eax
537
        jmp     try_end
1 ha 538
ok=$
2434 Serge 539
        xor     eax, eax
540
        inc     eax
1 ha 541
try_end=$
542
}
543
macro SimpleCriticalSection name
544
{
545
;  iglobal
546
    name  dd 0
547
          dd 0
548
    name#.type=2
549
;  endg
550
}
551
macro WaitSimpleCriticalSection name
552
{
553
  local start_wait,first_wait,inc_counter,end_wait
2434 Serge 554
        push    eax
555
        mov     eax, [TASK_BASE+second_base_address]
556
        mov     eax, [eax+TASKDATA.pid]
1 ha 557
start_wait=$
2434 Serge 558
        cli
559
        cmp     [name], dword 0
560
        jz      first_wait
561
        cmp     [name], eax
562
        jz      inc_counter
563
        sti
564
        call    change_task
565
        jmp     start_wait
1 ha 566
first_wait=$
2434 Serge 567
        mov     [name], eax
568
        mov     [name+4], dword 1
569
        jmp     end_wait
1 ha 570
inc_counter=$
2434 Serge 571
        inc     dword [name+4]
1 ha 572
end_wait=$
2434 Serge 573
        sti
574
        pop     eax
1 ha 575
}
576
macro ReleaseSimpleCriticalSection name
577
{
578
  local release_end
2434 Serge 579
        dec     dword [name+4]
580
        jnz     release_end
581
        mov     [name], dword 0
1 ha 582
release_end=$
583
}
584
macro TryWaitSimpleCriticalSection name ;result in eax and in flags
585
{
586
  local ok,try_end
2434 Serge 587
        mov     eax, [CURRENT_TASK+second_base_address]
588
        mov     eax, [eax+TASKDATA.pid]
589
        cmp     [name], eax
590
        jz      ok
591
        cmp     [name], 0
592
        jz      ok
593
        xor     eax, eax
594
        jmp     try_end
1 ha 595
ok=$
2434 Serge 596
        xor     eax, eax
597
        inc     eax
1 ha 598
try_end=$
599
}
600
_cli equ call MEM_HeapLock
601
_sti equ call MEM_HeapUnLock
602
end if
603